From eda3572089e71e0c5065831438c4999486838547 Mon Sep 17 00:00:00 2001 From: Marcelo Lira Date: Thu, 4 Aug 2011 12:18:02 -0300 Subject: Added tests for custom conversion and buffer protocol. It it inspired by some of PySide's QByteArray tests. --- tests/libsample/CMakeLists.txt | 1 + tests/libsample/bytearray.cpp | 208 +++++++++++++++++++++++ tests/libsample/bytearray.h | 83 +++++++++ tests/otherbinding/typesystem_other.xml | 4 +- tests/samplebinding/CMakeLists.txt | 1 + tests/samplebinding/bytearray_bufferprotocol.cpp | 27 +++ tests/samplebinding/bytearray_conversions.h | 28 +++ tests/samplebinding/bytearray_test.py | 145 ++++++++++++++++ tests/samplebinding/global.h | 1 + tests/samplebinding/typesystem_sample.xml | 104 ++++++++++++ 10 files changed, 601 insertions(+), 1 deletion(-) create mode 100644 tests/libsample/bytearray.cpp create mode 100644 tests/libsample/bytearray.h create mode 100644 tests/samplebinding/bytearray_bufferprotocol.cpp create mode 100644 tests/samplebinding/bytearray_conversions.h create mode 100644 tests/samplebinding/bytearray_test.py diff --git a/tests/libsample/CMakeLists.txt b/tests/libsample/CMakeLists.txt index 326b614cf..317a7d054 100644 --- a/tests/libsample/CMakeLists.txt +++ b/tests/libsample/CMakeLists.txt @@ -3,6 +3,7 @@ project(libsample) set(libsample_SRC abstract.cpp blackbox.cpp +bytearray.cpp bucket.cpp collector.cpp complex.cpp diff --git a/tests/libsample/bytearray.cpp b/tests/libsample/bytearray.cpp new file mode 100644 index 000000000..b0782d639 --- /dev/null +++ b/tests/libsample/bytearray.cpp @@ -0,0 +1,208 @@ +/* + * This file is part of the Shiboken Python Binding Generator project. + * + * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). + * + * Contact: PySide team + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include "bytearray.h" + +ByteArray::ByteArray() +{ + m_data = std::vector(1); + m_data[0] = '\0'; +} + +ByteArray::ByteArray(char c) +{ + m_data = std::vector(2); + m_data[0] = c; + m_data[1] = '\0'; +} + +ByteArray::ByteArray(const char* data) +{ + size_t len = strlen(data); + m_data = std::vector(len + 1); + memcpy(&m_data[0], data, len); + m_data[len] = '\0'; +} + +ByteArray::ByteArray(const char* data, int len) +{ + m_data = std::vector(len + 1); + memcpy(&m_data[0], data, len); + m_data[len] = '\0'; +} + +ByteArray::ByteArray(const ByteArray& other) +{ + m_data = std::vector(other.size() + 1); + memcpy(&m_data[0], &other.m_data[0], other.size()); + m_data[other.size()] = '\0'; +} + +int +ByteArray::size() const +{ + return m_data.size() - 1; +} + +char +ByteArray::at(int pos) const +{ + return m_data[pos]; +} + +const char* +ByteArray::data() const +{ + return &(m_data[0]); +} + +ByteArray& +ByteArray::append(char c) +{ + m_data.pop_back(); + m_data.push_back(c); + m_data.push_back('\0'); + return *this; +} + +ByteArray& +ByteArray::append(const char* data) +{ + m_data.pop_back(); + for (int i = 0; i < (int)strlen(data); ++i) + m_data.push_back(data[i]); + m_data.push_back('\0'); + return *this; +} + +ByteArray& +ByteArray::append(const char* data, int len) +{ + m_data.pop_back(); + for (int i = 0; i < len; ++i) + m_data.push_back(data[i]); + m_data.push_back('\0'); + return *this; +} + +ByteArray& +ByteArray::append(const ByteArray& other) +{ + m_data.pop_back(); + for (int i = 0; i < (int)other.m_data.size(); ++i) + m_data.push_back(other.m_data[i]); + m_data.push_back('\0'); + return *this; +} + +static bool compare(const std::vector& mine, const char* other) +{ + for (int i = 0; i < (int)mine.size() - 1; ++i) { + if (mine[i] != other[i]) + return false; + } + return true; +} + +bool +ByteArray::operator==(const ByteArray& other) const +{ + return compare(m_data, &other.m_data[0]); +} +bool +operator==(const ByteArray& ba1, const char* ba2) +{ + return compare(ba1.m_data, ba2); +} +bool +operator==(const char* ba1, const ByteArray& ba2) +{ + return compare(ba2.m_data, ba1); +} + +bool +ByteArray::operator!=(const ByteArray& other) const +{ + return !(m_data == other.m_data); +} +bool +operator!=(const ByteArray& ba1, const char* ba2) +{ + return !(ba1 == ba2); +} +bool +operator!=(const char* ba1, const ByteArray& ba2) +{ + return !(ba1 == ba2); +} + +ByteArray& +ByteArray::operator+=(char c) +{ + return append(c); +} +ByteArray& +ByteArray::operator+=(const char* data) +{ + return append(data); +} +ByteArray& +ByteArray::operator+=(const ByteArray& other) +{ + return append(other); +} + +ByteArray +operator+(const ByteArray& ba1, const ByteArray& ba2) +{ + return ByteArray(ba1) += ba2; +} +ByteArray +operator+(const ByteArray& ba1, const char* ba2) +{ + return ByteArray(ba1) += ByteArray(ba2); +} +ByteArray +operator+(const char* ba1, const ByteArray& ba2) +{ + return ByteArray(ba1) += ba2; +} +ByteArray +operator+(const ByteArray& ba1, char ba2) +{ + return ByteArray(ba1) += ByteArray(ba2); +} +ByteArray +operator+(char ba1, const ByteArray& ba2) +{ + return ByteArray(ba1) += ba2; +} + +unsigned int +ByteArray::hash(const ByteArray& byteArray) +{ + unsigned int result = 0; + for (int i = 0; i < (int)byteArray.m_data.size(); ++i) + result = 5 * result + byteArray.m_data[i]; + return result; +} diff --git a/tests/libsample/bytearray.h b/tests/libsample/bytearray.h new file mode 100644 index 000000000..a88adda6a --- /dev/null +++ b/tests/libsample/bytearray.h @@ -0,0 +1,83 @@ +/* + * This file is part of the Shiboken Python Binding Generator project. + * + * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). + * + * Contact: PySide team + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef BYTEARRAY_H +#define BYTEARRAY_H + +#include "str.h" +#include "libsamplemacros.h" +#include + +class LIBSAMPLE_API ByteArray +{ +public: + ByteArray(); + ByteArray(char data); + ByteArray(const char* data); + ByteArray(const char* data, int len); + ByteArray(const ByteArray& other); + + int size() const; + char at(int i) const; + char operator[](int i) const; + + const char* data() const; + + ByteArray& append(char c); + ByteArray& append(const char* data); + ByteArray& append(const char* data, int len); + ByteArray& append(const ByteArray& other); + + bool operator==(const ByteArray& other) const; + bool operator!=(const ByteArray& other) const; + + ByteArray& operator+=(char c); + ByteArray& operator+=(const char* data); + ByteArray& operator+=(const ByteArray& other); + + static unsigned int hash(const ByteArray& byteArray); +private: + std::vector m_data; + friend LIBSAMPLE_API bool operator==(const ByteArray& ba1, const char* ba2); + friend LIBSAMPLE_API bool operator==(const char* ba1, const ByteArray& ba2); + friend LIBSAMPLE_API bool operator!=(const ByteArray& ba1, const char* ba2); + friend LIBSAMPLE_API bool operator!=(const char* ba1, const ByteArray& ba2); + + friend LIBSAMPLE_API ByteArray operator+(const ByteArray& ba1, const ByteArray& ba2); + friend LIBSAMPLE_API ByteArray operator+(const ByteArray& ba1, const char* ba2); + friend LIBSAMPLE_API ByteArray operator+(const char* ba1, const ByteArray& ba2); + friend LIBSAMPLE_API ByteArray operator+(const ByteArray& ba1, char ba2); + friend LIBSAMPLE_API ByteArray operator+(char ba1, const ByteArray& ba2); +}; + +LIBSAMPLE_API bool operator==(const ByteArray& ba1, const char* ba2); +LIBSAMPLE_API bool operator==(const char* ba1, const ByteArray& ba2); +LIBSAMPLE_API bool operator!=(const ByteArray& ba1, const char* ba2); +LIBSAMPLE_API bool operator!=(const char* ba1, const ByteArray& ba2); + +LIBSAMPLE_API ByteArray operator+(const ByteArray& ba1, const ByteArray& ba2); +LIBSAMPLE_API ByteArray operator+(const ByteArray& ba1, const char* ba2); +LIBSAMPLE_API ByteArray operator+(const char* ba1, const ByteArray& ba2); +LIBSAMPLE_API ByteArray operator+(const ByteArray& ba1, char ba2); +LIBSAMPLE_API ByteArray operator+(char ba1, const ByteArray& ba2); + +#endif // BYTEARRAY_H diff --git a/tests/otherbinding/typesystem_other.xml b/tests/otherbinding/typesystem_other.xml index a1ef6b9a3..63ccdd518 100644 --- a/tests/otherbinding/typesystem_other.xml +++ b/tests/otherbinding/typesystem_other.xml @@ -9,5 +9,7 @@ + + + - diff --git a/tests/samplebinding/CMakeLists.txt b/tests/samplebinding/CMakeLists.txt index 23a3c456c..f63ecf981 100644 --- a/tests/samplebinding/CMakeLists.txt +++ b/tests/samplebinding/CMakeLists.txt @@ -14,6 +14,7 @@ ${CMAKE_CURRENT_BINARY_DIR}/sample/base4_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/base5_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/base6_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/blackbox_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/bytearray_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/bucket_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/collector_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/color_wrapper.cpp diff --git a/tests/samplebinding/bytearray_bufferprotocol.cpp b/tests/samplebinding/bytearray_bufferprotocol.cpp new file mode 100644 index 000000000..b3a6a83f4 --- /dev/null +++ b/tests/samplebinding/bytearray_bufferprotocol.cpp @@ -0,0 +1,27 @@ +#if PY_VERSION_HEX < 0x03000000 +// ByteArray buffer protocol functions +// See: http://www.python.org/dev/peps/pep-3118/ +extern "C" { +static Py_ssize_t SbkByteArray_segcountproc(PyObject* self, Py_ssize_t* lenp) +{ + if (lenp) + *lenp = self->ob_type->tp_as_sequence->sq_length(self); + return 1; +} +static Py_ssize_t SbkByteArray_readbufferproc(PyObject* self, Py_ssize_t segment, void** ptrptr) +{ + if (segment || !Shiboken::Object::isValid(self)) + return -1; + + ByteArray* cppSelf = Shiboken::Converter::toCpp(self); + *ptrptr = reinterpret_cast(const_cast(cppSelf->data())); + return cppSelf->size(); +} +PyBufferProcs SbkByteArrayBufferProc = { + /*bf_getreadbuffer*/ &SbkByteArray_readbufferproc, + /*bf_getwritebuffer*/ (writebufferproc)&SbkByteArray_readbufferproc, + /*bf_getsegcount*/ &SbkByteArray_segcountproc, + /*bf_getcharbuffer*/ (charbufferproc)&SbkByteArray_readbufferproc +}; +} +#endif diff --git a/tests/samplebinding/bytearray_conversions.h b/tests/samplebinding/bytearray_conversions.h new file mode 100644 index 000000000..79a070d7b --- /dev/null +++ b/tests/samplebinding/bytearray_conversions.h @@ -0,0 +1,28 @@ +namespace Shiboken { +inline bool Converter::checkType(PyObject* pyObj) +{ + return ValueTypeConverter::checkType(pyObj); +} +inline bool Converter::isConvertible(PyObject* pyObj) +{ + if (ValueTypeConverter::isConvertible(pyObj)) + return true; + SbkObjectType* shiboType = reinterpret_cast(SbkType()); + return Shiboken::Converter::checkType(pyObj) + || (ObjectType::isExternalConvertible(shiboType, pyObj)); +} +inline ByteArray Converter::toCpp(PyObject* pyObj) +{ + if (pyObj == Py_None) + return ByteArray(); + else if (PyObject_TypeCheck(pyObj, SbkType())) + return *Converter::toCpp(pyObj); + else if (PyString_Check(pyObj)) + return ByteArray(PyString_AS_STRING(pyObj), PyString_GET_SIZE(pyObj)); + return ValueTypeConverter::toCpp(pyObj); +} +inline PyObject* Converter::toPython(const ByteArray& cppObj) +{ + return ValueTypeConverter::toPython(cppObj); +} +} diff --git a/tests/samplebinding/bytearray_test.py b/tests/samplebinding/bytearray_test.py new file mode 100644 index 000000000..2eb99601f --- /dev/null +++ b/tests/samplebinding/bytearray_test.py @@ -0,0 +1,145 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# This file is part of the Shiboken Python Bindings Generator project. +# +# Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +# +# Contact: PySide team +# +# This program 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. Please +# review the following information to ensure the GNU Lesser General +# Public License version 2.1 requirements will be met: +# http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +# # +# This program 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 program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA + +import unittest +from os.path import isdir +from sample import ByteArray + + +class ByteArrayBufferProtocolTest(unittest.TestCase): + '''Tests ByteArray implementation of Python buffer protocol.''' + + def testByteArrayBufferProtocol(self): + # Tests ByteArray implementation of Python buffer protocol using the os.path.isdir + # function which an unicode object or other object implementing the Python buffer protocol. + isdir(ByteArray('/tmp')) + + +class ByteArrayConcatenationOperatorTest(unittest.TestCase): + '''Test cases for ByteArray concatenation with '+' operator.''' + + def testConcatByteArrayAndPythonString(self): + # Test concatenation of a ByteArray with a Python string, in this order. + ba = ByteArray('foo') + result = ba + '\x00bar' + self.assertEqual(type(result), ByteArray) + self.assertEqual(result, 'foo\x00bar') + + def testConcatPythonStringAndByteArray(self): + # Test concatenation of a Python string with a ByteArray, in this order. + concat_python_string_add_qbytearray_worked = True + ba = ByteArray('foo') + result = 'bar\x00' + ba + self.assertEqual(type(result), ByteArray) + self.assertEqual(result, 'bar\x00foo') + + +class ByteArrayOperatorEqual(unittest.TestCase): + '''TestCase for operator ByteArray == ByteArray.''' + + def testDefault(self): + # ByteArray() == ByteArray() + obj1 = ByteArray() + obj2 = ByteArray() + self.assertEqual(obj1, obj2) + + def testSimple(self): + # ByteArray(some_string) == ByteArray(some_string) + string = 'egg snakes' + self.assertEqual(ByteArray(string), ByteArray(string)) + + def testPyString(self): + # ByteArray(string) == string + string = 'my test string' + self.assertEqual(ByteArray(string), string) + + def testQString(self): + # ByteArray(string) == string + string = 'another test string' + self.assertEqual(ByteArray(string), string) + + +class ByteArrayOperatorAt(unittest.TestCase): + '''TestCase for operator ByteArray[]''' + + def testInRange(self): + # ByteArray[x] where x is a valid index. + string = 'abcdefgh' + obj = ByteArray(string) + for i in range(len(string)): + self.assertEqual(obj[i], string[i]) + + def testInRangeReverse(self): + # ByteArray[x] where x is a valid index (reverse order). + string = 'abcdefgh' + obj = ByteArray(string) + for i in range(len(string)-1, 0, -1): + self.assertEqual(obj[i], string[i]) + + def testOutOfRange(self): + # ByteArray[x] where x is out of index. + string = '1234567' + obj = ByteArray(string) + self.assertRaises(IndexError, lambda :obj[len(string)]) + + def testNullStrings(self): + ba = ByteArray('\x00') + self.assertEqual(ba.at(0), '\x00') + self.assertEqual(ba[0], '\x00') + + +class ByteArrayOperatorLen(unittest.TestCase): + '''Test case for __len__ operator of ByteArray''' + + def testBasic(self): + '''ByteArray __len__''' + self.assertEqual(len(ByteArray()), 0) + self.assertEqual(len(ByteArray('')), 0) + self.assertEqual(len(ByteArray(' ')), 1) + self.assertEqual(len(ByteArray('yabadaba')), 8) + + +class ByteArrayAndPythonStr(unittest.TestCase): + '''Test case for __str__ operator of ByteArray''' + + def testStrOperator(self): + '''ByteArray __str__''' + self.assertEqual(ByteArray().__str__(), '') + self.assertEqual(ByteArray('').__str__(), '') + self.assertEqual(ByteArray('aaa').__str__(), 'aaa') + + def testPythonStrAndNull(self): + s1 = "123\000321" + ba = ByteArray(s1) + s2 = ba.data() + self.assertEqual(s1, s2) + self.assertEqual(type(s1), type(s2)) + self.assertEqual(s1, ba) + self.assertNotEqual(type(s1), type(ba)) + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/samplebinding/global.h b/tests/samplebinding/global.h index 08f45b1df..164e992a9 100644 --- a/tests/samplebinding/global.h +++ b/tests/samplebinding/global.h @@ -1,5 +1,6 @@ #include "abstract.h" #include "blackbox.h" +#include "bytearray.h" #include "bucket.h" #include "collector.h" #include "complex.h" diff --git a/tests/samplebinding/typesystem_sample.xml b/tests/samplebinding/typesystem_sample.xml index 9624ba27a..547710a52 100644 --- a/tests/samplebinding/typesystem_sample.xml +++ b/tests/samplebinding/typesystem_sample.xml @@ -1422,6 +1422,110 @@ + + + + + + + + + + %0 = new %TYPE(PyString_AS_STRING(%PYARG_1), PyString_GET_SIZE(%PYARG_1)); + + + + + + + #if PY_VERSION_HEX < 0x03000000 + Shiboken::SbkType<ByteArray>()->tp_as_buffer = &SbkByteArrayBufferProc; + Shiboken::SbkType<ByteArray>()->tp_flags |= Py_TPFLAGS_HAVE_GETCHARBUFFER; + #endif + + + + + %PYARG_0 = PyString_FromStringAndSize(%CPPSELF.%FUNCTION_NAME(), %CPPSELF.size()); + + + + + + + + + + + + + + + + + + Shiboken::AutoDecRef data(PyUnicode_AsASCIIString(%PYARG_1)); + if (!data.isNull()) { + ByteArray ba(*%CPPSELF); + ba.append(PyString_AS_STRING(data.object()), PyString_GET_SIZE(data.object())); + %PYARG_0 = %CONVERTTOPYTHON[ByteArray](ba); + } + + + + + Shiboken::AutoDecRef data(PyUnicode_AsASCIIString(%PYARG_1)); + if (!data.isNull()) { + ByteArray ba(PyString_AS_STRING(data.object()), PyString_GET_SIZE(data.object())); + ba.append(*%CPPSELF); + %PYARG_0 = %CONVERTTOPYTHON[ByteArray](ba); + } + + + + + ByteArray ba(PyString_AS_STRING(%PYARG_1), PyString_GET_SIZE(%PYARG_1)); + %PYARG_0 = %CONVERTTOPYTHON[ByteArray](ba + *%CPPSELF); + + + + + + ByteArray ba(((PyObject*)%PYSELF)->ob_type->tp_name); + ba += '('; + Shiboken::AutoDecRef contents(PyObject_Repr(PyString_FromStringAndSize(%CPPSELF.data(), %CPPSELF.size()))); + ba += PyString_AS_STRING(contents.object()); + ba += ")"; + %PYARG_0 = PyString_FromStringAndSize(ba.data(), ba.size()); + + + + + + %PYARG_0 = PyString_FromStringAndSize(%CPPSELF.data(), %CPPSELF.size()); + + + + + + return %CPPSELF.size(); + + + + + if (_i < 0 || _i >= %CPPSELF.size()) { + PyErr_SetString(PyExc_IndexError, "index out of bounds"); + return 0; + } else { + char res[2]; + res[0] = %CPPSELF.at(_i); + res[1] = 0; + return PyString_FromStringAndSize(res, 1); + } + + + + -- cgit v1.2.3