From a9aa206b7b8ac4e69f8c46233b4080e00e845ff5 Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Mon, 27 May 2019 19:13:54 +0200 Subject: Move text-related code out of corelib/tools/ to corelib/text/ This includes byte array, string, char, unicode, locale, collation and regular expressions. Change-Id: I8b125fa52c8c513eb57a0f1298b91910e5a0d786 Reviewed-by: Volker Hilsheimer --- tests/auto/corelib/text/qbytearray/.gitattributes | 1 + tests/auto/corelib/text/qbytearray/.gitignore | 1 + .../corelib/text/qbytearray/android_testdata.qrc | 5 + tests/auto/corelib/text/qbytearray/qbytearray.pro | 16 + tests/auto/corelib/text/qbytearray/rfc3252.txt | 899 ++++++++ .../corelib/text/qbytearray/tst_qbytearray.cpp | 2343 ++++++++++++++++++++ .../corelib/text/qbytearray/tst_qbytearray_mac.mm | 97 + 7 files changed, 3362 insertions(+) create mode 100644 tests/auto/corelib/text/qbytearray/.gitattributes create mode 100644 tests/auto/corelib/text/qbytearray/.gitignore create mode 100644 tests/auto/corelib/text/qbytearray/android_testdata.qrc create mode 100644 tests/auto/corelib/text/qbytearray/qbytearray.pro create mode 100644 tests/auto/corelib/text/qbytearray/rfc3252.txt create mode 100644 tests/auto/corelib/text/qbytearray/tst_qbytearray.cpp create mode 100644 tests/auto/corelib/text/qbytearray/tst_qbytearray_mac.mm (limited to 'tests/auto/corelib/text/qbytearray') diff --git a/tests/auto/corelib/text/qbytearray/.gitattributes b/tests/auto/corelib/text/qbytearray/.gitattributes new file mode 100644 index 0000000000..e04709aa2e --- /dev/null +++ b/tests/auto/corelib/text/qbytearray/.gitattributes @@ -0,0 +1 @@ +rfc3252.txt -crlf diff --git a/tests/auto/corelib/text/qbytearray/.gitignore b/tests/auto/corelib/text/qbytearray/.gitignore new file mode 100644 index 0000000000..3de7c3fab5 --- /dev/null +++ b/tests/auto/corelib/text/qbytearray/.gitignore @@ -0,0 +1 @@ +tst_qbytearray diff --git a/tests/auto/corelib/text/qbytearray/android_testdata.qrc b/tests/auto/corelib/text/qbytearray/android_testdata.qrc new file mode 100644 index 0000000000..5d42f0f627 --- /dev/null +++ b/tests/auto/corelib/text/qbytearray/android_testdata.qrc @@ -0,0 +1,5 @@ + + + rfc3252.txt + + diff --git a/tests/auto/corelib/text/qbytearray/qbytearray.pro b/tests/auto/corelib/text/qbytearray/qbytearray.pro new file mode 100644 index 0000000000..c2101b0611 --- /dev/null +++ b/tests/auto/corelib/text/qbytearray/qbytearray.pro @@ -0,0 +1,16 @@ +CONFIG += testcase +TARGET = tst_qbytearray +QT = core-private testlib +SOURCES = tst_qbytearray.cpp + +TESTDATA += rfc3252.txt + +mac { + OBJECTIVE_SOURCES += tst_qbytearray_mac.mm + LIBS += -framework Foundation +} + +android:!android-embedded { + RESOURCES += \ + android_testdata.qrc +} diff --git a/tests/auto/corelib/text/qbytearray/rfc3252.txt b/tests/auto/corelib/text/qbytearray/rfc3252.txt new file mode 100644 index 0000000000..b80c61bf0a --- /dev/null +++ b/tests/auto/corelib/text/qbytearray/rfc3252.txt @@ -0,0 +1,899 @@ + + + + + + +Network Working Group H. Kennedy +Request for Comments: 3252 Mimezine +Category: Informational 1 April 2002 + + + Binary Lexical Octet Ad-hoc Transport + +Status of this Memo + + This memo provides information for the Internet community. It does + not specify an Internet standard of any kind. Distribution of this + memo is unlimited. + +Copyright Notice + + Copyright (C) The Internet Society (2002). All Rights Reserved. + +Abstract + + This document defines a reformulation of IP and two transport layer + protocols (TCP and UDP) as XML applications. + +1. Introduction + +1.1. Overview + + This document describes the Binary Lexical Octet Ad-hoc Transport + (BLOAT): a reformulation of a widely-deployed network-layer protocol + (IP [RFC791]), and two associated transport layer protocols (TCP + [RFC793] and UDP [RFC768]) as XML [XML] applications. It also + describes methods for transporting BLOAT over Ethernet and IEEE 802 + networks as well as encapsulating BLOAT in IP for gatewaying BLOAT + across the public Internet. + +1.2. Motivation + + The wild popularity of XML as a basis for application-level protocols + such as the Blocks Extensible Exchange Protocol [RFC3080], the Simple + Object Access Protocol [SOAP], and Jabber [JABBER] prompted + investigation into the possibility of extending the use of XML in the + protocol stack. Using XML at both the transport and network layer in + addition to the application layer would provide for an amazing amount + of power and flexibility while removing dependencies on proprietary + and hard-to-understand binary protocols. This protocol unification + would also allow applications to use a single XML parser for all + aspects of their operation, eliminating developer time spent figuring + out the intricacies of each new protocol, and moving the hard work of + + + + +Kennedy Informational [Page 1] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + parsing to the XML toolset. The use of XML also mitigates concerns + over "network vs. host" byte ordering which is at the root of many + network application bugs. + +1.3. Relation to Existing Protocols + + The reformulations specified in this RFC follow as closely as + possible the spirit of the RFCs on which they are based, and so MAY + contain elements or attributes that would not be needed in a pure + reworking (e.g. length attributes, which are implicit in XML.) + + The layering of network and transport protocols are maintained in + this RFC despite the optimizations that could be made if the line + were somewhat blurred (i.e. merging TCP and IP into a single, larger + element in the DTD) in order to foster future use of this protocol as + a basis for reformulating other protocols (such as ICMP.) + + Other than the encoding, the behavioral aspects of each of the + existing protocols remain unchanged. Routing, address spaces, TCP + congestion control, etc. behave as specified in the extant standards. + Adapting to new standards and experimental algorithm heuristics for + improving performance will become much easier once the move to BLOAT + has been completed. + +1.4. Requirement Levels + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in BCP 14, RFC 2119 + [RFC2119]. + +2. IPoXML + + This protocol MUST be implemented to be compliant with this RFC. + IPoXML is the root protocol REQUIRED for effective use of TCPoXML + (section 3.) and higher-level application protocols. + + The DTD for this document type can be found in section 7.1. + + The routing of IPoXML can be easily implemented on hosts with an XML + parser, as the regular structure lends itself handily to parsing and + validation of the document/datagram and then processing the + destination address, TTL, and checksum before sending it on to its + next-hop. + + The reformulation of IPv4 was chosen over IPv6 [RFC2460] due to the + wider deployment of IPv4 and the fact that implementing IPv6 as XML + would have exceeded the 1500 byte Ethernet MTU. + + + +Kennedy Informational [Page 2] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + All BLOAT implementations MUST use - and specify - the UTF-8 encoding + of RFC 2279 [RFC2279]. All BLOAT document/datagrams MUST be well- + formed and include the XMLDecl. + +2.1. IP Description + + A number of items have changed (for the better) from the original IP + specification. Bit-masks, where present have been converted into + human-readable values. IP addresses are listed in their dotted- + decimal notation [RFC1123]. Length and checksum values are present + as decimal integers. + + To calculate the length and checksum fields of the IP element, a + canonicalized form of the element MUST be used. The canonical form + SHALL have no whitespace (including newline characters) between + elements and only one space character between attributes. There + SHALL NOT be a space following the last attribute in an element. + + An iterative method SHOULD be used to calculate checksums, as the + length field will vary based on the size of the checksum. + + The payload element bears special attention. Due to the character + set restrictions of XML, the payload of IP datagrams (which MAY + contain arbitrary data) MUST be encoded for transport. This RFC + REQUIRES the contents of the payload to be encoded in the base-64 + encoding of RFC 2045 [RFC2045], but removes the requirement that the + encoded output MUST be wrapped on 76-character lines. + + + + + + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 3] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +2.2. Example Datagram + + The following is an example IPoXML datagram with an empty payload: + + + + +
+ + + + + + + + + + + + + + + +
+ + +
+ +3. TCPoXML + + This protocol MUST be implemented to be compliant with this RFC. The + DTD for this document type can be found in section 7.2. + +3.1. TCP Description + + A number of items have changed from the original TCP specification. + Bit-masks, where present have been converted into human-readable + values. Length and checksum and port values are present as decimal + integers. + + To calculate the length and checksum fields of the TCP element, a + canonicalized form of the element MUST be used as in section 2.1. + + An iterative method SHOULD be used to calculate checksums as in + section 2.1. + + The payload element MUST be encoded as in section 2.1. + + + +Kennedy Informational [Page 4] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + The TCP offset element was expanded to a maximum of 255 from 16 to + allow for the increased size of the header in XML. + + TCPoXML datagrams encapsulated by IPoXML MAY omit the header + as well as the declaration. + +3.2. Example Datagram + + The following is an example TCPoXML datagram with an empty payload: + + + + + + + + + + + + + + + + + + + + + + + + +4. UDPoXML + + This protocol MUST be implemented to be compliant with this RFC. The + DTD for this document type can be found in section 7.3. + +4.1. UDP Description + + A number of items have changed from the original UDP specification. + Bit-masks, where present have been converted into human-readable + values. Length and checksum and port values are present as decimal + integers. + + + + + + + +Kennedy Informational [Page 5] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + To calculate the length and checksum fields of the UDP element, a + canonicalized form of the element MUST be used as in section 2.1. An + iterative method SHOULD be used to calculate checksums as in section + 2.1. + + The payload element MUST be encoded as in section 2.1. + + UDPoXML datagrams encapsulated by IPoXML MAY omit the header + as well as the declaration. + +4.2. Example Datagram + + The following is an example UDPoXML datagram with an empty payload: + + + + + + + + + + + + + + +5. Network Transport + + This document provides for the transmission of BLOAT datagrams over + two common families of physical layer transport. Future RFCs will + address additional transports as routing vendors catch up to the + specification, and we begin to see BLOAT routed across the Internet + backbone. + +5.1. Ethernet + + BLOAT is encapsulated in Ethernet datagrams as in [RFC894] with the + exception that the type field of the Ethernet frame MUST contain the + value 0xBEEF. The first 5 octets of the Ethernet frame payload will + be 0x3c 3f 78 6d 6c (" + --> + + + + +Kennedy Informational [Page 7] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 9] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + + + + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 10] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + + + + + + + + + + + +7.2. TCPoXML DTD + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 11] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 12] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + + + + + + + + + + + + + + + + + + +7.3. UDPoXML DTD + + + + + + + + + + + + + + + +Kennedy Informational [Page 13] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +8. Security Considerations + + XML, as a subset of SGML, has the same security considerations as + specified in SGML Media Types [RFC1874]. Security considerations + that apply to IP, TCP and UDP also likely apply to BLOAT as it does + not attempt to correct for issues not related to message format. + +9. References + + [JABBER] Miller, J., "Jabber", draft-miller-jabber-00.txt, + February 2002. (Work in Progress) + + [RFC768] Postel, J., "User Datagram Protocol", STD 6, RFC 768, + August 1980. + + [RFC791] Postel, J., "Internet Protocol", STD 5, RFC 791, + September 1981. + + [RFC793] Postel, J., "Transmission Control Protocol", STD 7, RFC + 793, September 1981. + + [RFC894] Hornig, C., "Standard for the Transmission of IP + Datagrams over Ethernet Networks.", RFC 894, April 1984. + + [RFC1042] Postel, J. and J. Reynolds, "Standard for the + Transmission of IP Datagrams Over IEEE 802 Networks", STD + 43, RFC 1042, February 1988. + + [RFC1123] Braden, R., "Requirements for Internet Hosts - + Application and Support", RFC 1123, October 1989. + + [RFC1874] Levinson, E., "SGML Media Types", RFC 1874, December + 1995. + + [RFC2003] Perkins, C., "IP Encapsulation within IP", RFC 2003, + October 1996. + + [RFC2045] Freed, N. and N. Borenstein, "Multipurpose Internet Mail + Extensions (MIME) Part One: Format of Internet Message + Bodies", RFC 2045, November 1996. + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + + [RFC2279] Yergeau, F., "UTF-8, a transformation format of ISO + 10646", RFC 2279, January 1998. + + + + + +Kennedy Informational [Page 14] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + + [RFC2460] Deering, S. and R. Hinden, "Internet Protocol, Version 6 + (IPv6) Specification", RFC 2460, December 1998. + + [RFC3080] Rose, M., "The Blocks Extensible Exchange Protocol Core", + RFC 3080, March 2001. + + [SOAP] Box, D., Ehnebuske, D., Kakivaya, G., Layman, A., + Mendelsohn, N., Nielsen, H. F., Thatte, S. Winer, D., + "Simple Object Access Protocol (SOAP) 1.1" World Wide Web + Consortium Note, May 2000 http://www.w3.org/TR/SOAP/ + + [XML] Bray, T., Paoli, J., Sperberg-McQueen, C. M., "Extensible + Markup Language (XML)" World Wide Web Consortium + Recommendation REC- xml-19980210. + http://www.w3.org/TR/1998/REC-xml-19980210 + +10. Author's Address + + Hugh Kennedy + Mimezine + 1060 West Addison + Chicago, IL 60613 + USA + + EMail: kennedyh@engin.umich.edu + + + + + + + + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 15] + +RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002 + + +11. Full Copyright Statement + + Copyright (C) The Internet Society (2002). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph are + included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assigns. + + This document and the information contained herein is provided on an + "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + + + + + + + + + + + + + +Kennedy Informational [Page 16] + diff --git a/tests/auto/corelib/text/qbytearray/tst_qbytearray.cpp b/tests/auto/corelib/text/qbytearray/tst_qbytearray.cpp new file mode 100644 index 0000000000..90dfcaef25 --- /dev/null +++ b/tests/auto/corelib/text/qbytearray/tst_qbytearray.cpp @@ -0,0 +1,2343 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2016 Intel Corporation. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include +#include +#include +#include +#include + +class tst_QByteArray : public QObject +{ + Q_OBJECT + +public: + tst_QByteArray(); +private slots: + void swap(); + void qChecksum_data(); + void qChecksum(); + void qCompress_data(); +#ifndef QT_NO_COMPRESS + void qCompress(); + void qUncompressCorruptedData_data(); + void qUncompressCorruptedData(); + void qCompressionZeroTermination(); +#endif + void constByteArray(); + void leftJustified(); + void rightJustified(); + void setNum(); + void startsWith_data(); + void startsWith(); + void startsWith_char(); + void endsWith_data(); + void endsWith(); + void endsWith_char(); + void reverseIterators(); + void split_data(); + void split(); + void base64_data(); + void base64(); + void fromBase64_data(); + void fromBase64(); + void qvsnprintf(); + void qstrlen(); + void qstrnlen(); + void qstrcpy(); + void qstrncpy(); + void qstricmp_data(); + void qstricmp(); + void qstricmp_singularities(); + void qstrnicmp_singularities(); + void chop_data(); + void chop(); + void prepend(); + void prependExtended_data(); + void prependExtended(); + void append(); + void appendExtended_data(); + void appendExtended(); + void insert(); + void insertExtended_data(); + void insertExtended(); + void remove_data(); + void remove(); + void replace_data(); + void replace(); + void replaceWithSpecifiedLength(); + void indexOf_data(); + void indexOf(); + void lastIndexOf_data(); + void lastIndexOf(); + void toULong_data(); + void toULong(); + void toULongLong_data(); + void toULongLong(); + + void number(); + void toInt_data(); + void toInt(); + void toDouble_data(); + void toDouble(); + void blockSizeCalculations(); + + void resizeAfterFromRawData(); + void appendAfterFromRawData(); + void toFromHex_data(); + void toFromHex(); + void toFromPercentEncoding(); + void fromPercentEncoding_data(); + void fromPercentEncoding(); + void toPercentEncoding_data(); + void toPercentEncoding(); + void toPercentEncoding2_data(); + void toPercentEncoding2(); + + void compare_data(); + void compare(); + void compareCharStar_data(); + void compareCharStar(); + + void repeatedSignature() const; + void repeated() const; + void repeated_data() const; + + void byteRefDetaching() const; + + void reserve(); + void reserveExtended_data(); + void reserveExtended(); + void movablity_data(); + void movablity(); + void literals(); + void toUpperLower_data(); + void toUpperLower(); + void isUpper(); + void isLower(); + + void macTypes(); + + void stdString(); +}; + +static const struct StaticByteArrays { + struct Standard { + QByteArrayData data; + const char string[8]; + } standard; + struct NotNullTerminated { + QByteArrayData data; + const char string[8]; + } notNullTerminated; + struct Shifted { + QByteArrayData data; + const char dummy; // added to change offset of string + const char string[8]; + } shifted; + struct ShiftedNotNullTerminated { + QByteArrayData data; + const char dummy; // added to change offset of string + const char string[8]; + } shiftedNotNullTerminated; + +} statics = {{Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER(4), "data"} + ,{Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER(4), "dataBAD"} + ,{Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(4, sizeof(QByteArrayData) + sizeof(char)), 0, "data"} + ,{Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(4, sizeof(QByteArrayData) + sizeof(char)), 0, "dataBAD"} + }; + +static const QByteArrayDataPtr staticStandard = { const_cast(&statics.standard.data) }; +static const QByteArrayDataPtr staticNotNullTerminated = { const_cast(&statics.notNullTerminated.data) }; +static const QByteArrayDataPtr staticShifted = { const_cast(&statics.shifted.data) }; +static const QByteArrayDataPtr staticShiftedNotNullTerminated = { const_cast(&statics.shiftedNotNullTerminated.data) }; + +template const T &verifyZeroTermination(const T &t) { return t; } + +QByteArray verifyZeroTermination(const QByteArray &ba) +{ + // This test does some evil stuff, it's all supposed to work. + + QByteArray::DataPtr baDataPtr = const_cast(ba).data_ptr(); + + // Skip if isStatic() or fromRawData(), as those offer no guarantees + if (baDataPtr->ref.isStatic() + || baDataPtr->offset != QByteArray().data_ptr()->offset) + return ba; + + int baSize = ba.size(); + char baTerminator = ba.constData()[baSize]; + if ('\0' != baTerminator) + return QString::fromLatin1( + "*** Result ('%1') not null-terminated: 0x%2 ***").arg(QString::fromLatin1(ba)) + .arg(baTerminator, 2, 16, QChar('0')).toLatin1(); + + // Skip mutating checks on shared strings + if (baDataPtr->ref.isShared()) + return ba; + + const char *baData = ba.constData(); + const QByteArray baCopy(baData, baSize); // Deep copy + + const_cast(baData)[baSize] = 'x'; + if ('x' != ba.constData()[baSize]) { + return "*** Failed to replace null-terminator in " + "result ('" + ba + "') ***"; + } + if (ba != baCopy) { + return "*** Result ('" + ba + "') differs from its copy " + "after null-terminator was replaced ***"; + } + const_cast(baData)[baSize] = '\0'; // Restore sanity + + return ba; +} + +// Overriding QTest's QCOMPARE, to check QByteArray for null termination +#undef QCOMPARE +#define QCOMPARE(actual, expected) \ + do { \ + if (!QTest::qCompare(verifyZeroTermination(actual), expected, \ + #actual, #expected, __FILE__, __LINE__)) \ + return; \ + } while (0) \ + /**/ +#undef QTEST +#define QTEST(actual, testElement) \ + do { \ + if (!QTest::qTest(verifyZeroTermination(actual), testElement, \ + #actual, #testElement, __FILE__, __LINE__)) \ + return; \ + } while (0) \ + /**/ + +tst_QByteArray::tst_QByteArray() +{ +} + +void tst_QByteArray::qChecksum_data() +{ + QTest::addColumn("data"); + QTest::addColumn("len"); + QTest::addColumn("standard"); + QTest::addColumn("checksum"); + + // Examples from ISO 14443-3 + QTest::newRow("1") << QByteArray("\x00\x00") << 2U << Qt::ChecksumItuV41 << 0x1EA0U; + QTest::newRow("2") << QByteArray("\x12\x34") << 2U << Qt::ChecksumItuV41 << 0xCF26U; + QTest::newRow("3") << QByteArray("\x00\x00\x00") << 3U << Qt::ChecksumIso3309 << 0xC6CCU; + QTest::newRow("4") << QByteArray("\x0F\xAA\xFF") << 3U << Qt::ChecksumIso3309 << 0xD1FCU; + QTest::newRow("5") << QByteArray("\x0A\x12\x34\x56") << 4U << Qt::ChecksumIso3309 << 0xF62CU; +} + +void tst_QByteArray::qChecksum() +{ + QFETCH(QByteArray, data); + QFETCH(uint, len); + QFETCH(Qt::ChecksumType, standard); + QFETCH(uint, checksum); + + if (standard == Qt::ChecksumIso3309) { + QCOMPARE(::qChecksum(data.constData(), len), static_cast(checksum)); + } + QCOMPARE(::qChecksum(data.constData(), len, standard), static_cast(checksum)); +} + +void tst_QByteArray::qCompress_data() +{ + QTest::addColumn("ba"); + + const int size1 = 1024*1024; + QByteArray ba1( size1, 0 ); + + QTest::newRow( "00" ) << QByteArray(); + + int i; + for ( i=0; i("in"); + + QTest::newRow("0x00000000") << QByteArray("\x00\x00\x00\x00", 4); + QTest::newRow("0x000000ff") << QByteArray("\x00\x00\x00\xff", 4); + QTest::newRow("0x3f000000") << QByteArray("\x3f\x00\x00\x00", 4); + QTest::newRow("0x3fffffff") << QByteArray("\x3f\xff\xff\xff", 4); + QTest::newRow("0x7fffff00") << QByteArray("\x7f\xff\xff\x00", 4); + QTest::newRow("0x7fffffff") << QByteArray("\x7f\xff\xff\xff", 4); + QTest::newRow("0x80000000") << QByteArray("\x80\x00\x00\x00", 4); + QTest::newRow("0x800000ff") << QByteArray("\x80\x00\x00\xff", 4); + QTest::newRow("0xcf000000") << QByteArray("\xcf\x00\x00\x00", 4); + QTest::newRow("0xcfffffff") << QByteArray("\xcf\xff\xff\xff", 4); + QTest::newRow("0xffffff00") << QByteArray("\xff\xff\xff\x00", 4); + QTest::newRow("0xffffffff") << QByteArray("\xff\xff\xff\xff", 4); +} + +// Corrupt data causes this test to lock up on HP-UX / PA-RISC with gcc, +// SOLARIS, and Windows. +// This test is expected to produce some warning messages in the test output. +void tst_QByteArray::qUncompressCorruptedData() +{ +#if !(defined(Q_OS_HPUX) && !defined(__ia64) && defined(Q_CC_GNU)) && !defined(Q_OS_SOLARIS) && !defined(Q_OS_WIN) + QFETCH(QByteArray, in); + + QByteArray res; + res = ::qUncompress(in); + QCOMPARE(res, QByteArray()); + + res = ::qUncompress(in + "blah"); + QCOMPARE(res, QByteArray()); +#else + QSKIP("This test freezes on this platform"); +#endif +} + +void tst_QByteArray::qCompressionZeroTermination() +{ + QString s = "Hello, I'm a string."; + QByteArray ba = ::qUncompress(::qCompress(s.toLocal8Bit())); + QVERIFY((int) *(ba.data() + ba.size()) == 0); +} + +#endif + +void tst_QByteArray::constByteArray() +{ + const char *ptr = "abc"; + QByteArray cba = QByteArray::fromRawData(ptr, 3); + QVERIFY(cba.constData() == ptr); + cba.squeeze(); + QVERIFY(cba.constData() == ptr); + cba.detach(); + QVERIFY(cba.size() == 3); + QVERIFY(cba.capacity() == 3); + QVERIFY(cba.constData() != ptr); + QVERIFY(cba.constData()[0] == 'a'); + QVERIFY(cba.constData()[1] == 'b'); + QVERIFY(cba.constData()[2] == 'c'); + QVERIFY(cba.constData()[3] == '\0'); +} + +void tst_QByteArray::leftJustified() +{ + QByteArray a; + a = "ABC"; + QCOMPARE(a.leftJustified(5,'-'), QByteArray("ABC--")); + QCOMPARE(a.leftJustified(4,'-'), QByteArray("ABC-")); + QCOMPARE(a.leftJustified(4), QByteArray("ABC ")); + QCOMPARE(a.leftJustified(3), QByteArray("ABC")); + QCOMPARE(a.leftJustified(2), QByteArray("ABC")); + QCOMPARE(a.leftJustified(1), QByteArray("ABC")); + QCOMPARE(a.leftJustified(0), QByteArray("ABC")); + + QByteArray n; + QVERIFY(!n.leftJustified(3).isNull()); // I expected true + QCOMPARE(a.leftJustified(4,' ',true), QByteArray("ABC ")); + QCOMPARE(a.leftJustified(3,' ',true), QByteArray("ABC")); + QCOMPARE(a.leftJustified(2,' ',true), QByteArray("AB")); + QCOMPARE(a.leftJustified(1,' ',true), QByteArray("A")); + QCOMPARE(a.leftJustified(0,' ',true), QByteArray("")); +} + +void tst_QByteArray::rightJustified() +{ + QByteArray a; + a="ABC"; + QCOMPARE(a.rightJustified(5,'-'),QByteArray("--ABC")); + QCOMPARE(a.rightJustified(4,'-'),QByteArray("-ABC")); + QCOMPARE(a.rightJustified(4),QByteArray(" ABC")); + QCOMPARE(a.rightJustified(3),QByteArray("ABC")); + QCOMPARE(a.rightJustified(2),QByteArray("ABC")); + QCOMPARE(a.rightJustified(1),QByteArray("ABC")); + QCOMPARE(a.rightJustified(0),QByteArray("ABC")); + + QByteArray n; + QVERIFY(!n.rightJustified(3).isNull()); // I expected true + QCOMPARE(a.rightJustified(4,'-',true),QByteArray("-ABC")); + QCOMPARE(a.rightJustified(4,' ',true),QByteArray(" ABC")); + QCOMPARE(a.rightJustified(3,' ',true),QByteArray("ABC")); + QCOMPARE(a.rightJustified(2,' ',true),QByteArray("AB")); + QCOMPARE(a.rightJustified(1,' ',true),QByteArray("A")); + QCOMPARE(a.rightJustified(0,' ',true),QByteArray("")); + QCOMPARE(a,QByteArray("ABC")); +} + +void tst_QByteArray::setNum() +{ + QByteArray a; + QCOMPARE(a.setNum(-1), QByteArray("-1")); + QCOMPARE(a.setNum(0), QByteArray("0")); + QCOMPARE(a.setNum(0, 2), QByteArray("0")); + QCOMPARE(a.setNum(0, 36), QByteArray("0")); + QCOMPARE(a.setNum(1), QByteArray("1")); + QCOMPARE(a.setNum(35, 36), QByteArray("z")); + QCOMPARE(a.setNum(37, 2), QByteArray("100101")); + QCOMPARE(a.setNum(37, 36), QByteArray("11")); + + // Negative numbers are only properly supported for base 10. + QCOMPARE(a.setNum(short(-1), 16), QByteArray("ffff")); + QCOMPARE(a.setNum(int(-1), 16), QByteArray("ffffffff")); + QCOMPARE(a.setNum(qlonglong(-1), 16), QByteArray("ffffffffffffffff")); + + QCOMPARE(a.setNum(short(-1), 10), QByteArray("-1")); + QCOMPARE(a.setNum(int(-1), 10), QByteArray("-1")); + QCOMPARE(a.setNum(qlonglong(-1), 10), QByteArray("-1")); + + QCOMPARE(a.setNum(-123), QByteArray("-123")); + QCOMPARE(a.setNum(0x123,16), QByteArray("123")); + QCOMPARE(a.setNum((short)123), QByteArray("123")); + + QCOMPARE(a.setNum(1.23), QByteArray("1.23")); + QCOMPARE(a.setNum(1.234567), QByteArray("1.23457")); + + // Note that there are no 'long' overloads, so not all of the + // QString::setNum() tests can be re-used. + QCOMPARE(a.setNum(Q_INT64_C(123)), QByteArray("123")); + // 2^40 == 1099511627776 + QCOMPARE(a.setNum(Q_INT64_C(-1099511627776)), QByteArray("-1099511627776")); + QCOMPARE(a.setNum(Q_UINT64_C(1099511627776)), QByteArray("1099511627776")); + QCOMPARE(a.setNum(Q_INT64_C(9223372036854775807)), // LLONG_MAX + QByteArray("9223372036854775807")); + QCOMPARE(a.setNum(-Q_INT64_C(9223372036854775807) - Q_INT64_C(1)), + QByteArray("-9223372036854775808")); + QCOMPARE(a.setNum(Q_UINT64_C(18446744073709551615)), // ULLONG_MAX + QByteArray("18446744073709551615")); + QCOMPARE(a.setNum(0.000000000931322574615478515625), QByteArray("9.31323e-10")); +} + +void tst_QByteArray::startsWith_data() +{ + QTest::addColumn("ba"); + QTest::addColumn("sw"); + QTest::addColumn("result"); + + QTest::newRow("01") << QByteArray() << QByteArray() << true; + QTest::newRow("02") << QByteArray() << QByteArray("") << true; + QTest::newRow("03") << QByteArray() << QByteArray("hallo") << false; + + QTest::newRow("04") << QByteArray("") << QByteArray() << true; + QTest::newRow("05") << QByteArray("") << QByteArray("") << true; + QTest::newRow("06") << QByteArray("") << QByteArray("h") << false; + + QTest::newRow("07") << QByteArray("hallo") << QByteArray("h") << true; + QTest::newRow("08") << QByteArray("hallo") << QByteArray("hallo") << true; + QTest::newRow("09") << QByteArray("hallo") << QByteArray("") << true; + QTest::newRow("10") << QByteArray("hallo") << QByteArray("hallohallo") << false; + QTest::newRow("11") << QByteArray("hallo") << QByteArray() << true; +} + +void tst_QByteArray::startsWith() +{ + QFETCH(QByteArray, ba); + QFETCH(QByteArray, sw); + QFETCH(bool, result); + + QVERIFY(ba.startsWith(sw) == result); + + if (sw.isNull()) { + QVERIFY(ba.startsWith((char*)0) == result); + } else { + QVERIFY(ba.startsWith(sw.data()) == result); + } +} + +void tst_QByteArray::startsWith_char() +{ + QVERIFY(QByteArray("hallo").startsWith('h')); + QVERIFY(!QByteArray("hallo").startsWith('\0')); + QVERIFY(!QByteArray("hallo").startsWith('o')); + QVERIFY(QByteArray("h").startsWith('h')); + QVERIFY(!QByteArray("h").startsWith('\0')); + QVERIFY(!QByteArray("h").startsWith('o')); + QVERIFY(!QByteArray("hallo").startsWith('l')); + QVERIFY(!QByteArray("").startsWith('\0')); + QVERIFY(!QByteArray("").startsWith('a')); + QVERIFY(!QByteArray().startsWith('a')); + QVERIFY(!QByteArray().startsWith('\0')); +} + +void tst_QByteArray::endsWith_data() +{ + QTest::addColumn("ba"); + QTest::addColumn("sw"); + QTest::addColumn("result"); + + QTest::newRow("01") << QByteArray() << QByteArray() << true; + QTest::newRow("02") << QByteArray() << QByteArray("") << true; + QTest::newRow("03") << QByteArray() << QByteArray("hallo") << false; + + QTest::newRow("04") << QByteArray("") << QByteArray() << true; + QTest::newRow("05") << QByteArray("") << QByteArray("") << true; + QTest::newRow("06") << QByteArray("") << QByteArray("h") << false; + + QTest::newRow("07") << QByteArray("hallo") << QByteArray("o") << true; + QTest::newRow("08") << QByteArray("hallo") << QByteArray("hallo") << true; + QTest::newRow("09") << QByteArray("hallo") << QByteArray("") << true; + QTest::newRow("10") << QByteArray("hallo") << QByteArray("hallohallo") << false; + QTest::newRow("11") << QByteArray("hallo") << QByteArray() << true; +} + +void tst_QByteArray::endsWith() +{ + QFETCH(QByteArray, ba); + QFETCH(QByteArray, sw); + QFETCH(bool, result); + + QVERIFY(ba.endsWith(sw) == result); + + if (sw.isNull()) { + QVERIFY(ba.endsWith((char*)0) == result); + } else { + QVERIFY(ba.endsWith(sw.data()) == result); + } +} + +void tst_QByteArray::endsWith_char() +{ + QVERIFY(QByteArray("hallo").endsWith('o')); + QVERIFY(!QByteArray("hallo").endsWith('\0')); + QVERIFY(!QByteArray("hallo").endsWith('h')); + QVERIFY(QByteArray("h").endsWith('h')); + QVERIFY(!QByteArray("h").endsWith('\0')); + QVERIFY(!QByteArray("h").endsWith('o')); + QVERIFY(!QByteArray("hallo").endsWith('l')); + QVERIFY(!QByteArray("").endsWith('\0')); + QVERIFY(!QByteArray("").endsWith('a')); + QVERIFY(!QByteArray().endsWith('a')); + QVERIFY(!QByteArray().endsWith('\0')); +} + +void tst_QByteArray::reverseIterators() +{ + QByteArray s = "1234"; + QByteArray sr = s; + std::reverse(sr.begin(), sr.end()); + const QByteArray &csr = sr; + QVERIFY(std::equal(s.begin(), s.end(), sr.rbegin())); + QVERIFY(std::equal(s.begin(), s.end(), sr.crbegin())); + QVERIFY(std::equal(s.begin(), s.end(), csr.rbegin())); + QVERIFY(std::equal(sr.rbegin(), sr.rend(), s.begin())); + QVERIFY(std::equal(sr.crbegin(), sr.crend(), s.begin())); + QVERIFY(std::equal(csr.rbegin(), csr.rend(), s.begin())); +} + +void tst_QByteArray::split_data() +{ + QTest::addColumn("sample"); + QTest::addColumn("size"); + + QTest::newRow("1") << QByteArray("-rw-r--r-- 1 0 0 519240 Jul 9 2002 bigfile") << 14; + QTest::newRow("2") << QByteArray("abcde") << 1; + QTest::newRow("one empty") << QByteArray("") << 1; + QTest::newRow("two empty") << QByteArray(" ") << 2; + QTest::newRow("three empty") << QByteArray(" ") << 3; + +} + +void tst_QByteArray::split() +{ + QFETCH(QByteArray, sample); + QFETCH(int, size); + + QList list = sample.split(' '); + QCOMPARE(list.count(), size); +} + +void tst_QByteArray::swap() +{ + QByteArray b1 = "b1", b2 = "b2"; + b1.swap(b2); + QCOMPARE(b1, QByteArray("b2")); + QCOMPARE(b2, QByteArray("b1")); +} + +void tst_QByteArray::base64_data() +{ + QTest::addColumn("rawdata"); + QTest::addColumn("base64"); + + QTest::newRow("1") << QByteArray("") << QByteArray(""); + QTest::newRow("2") << QByteArray("1") << QByteArray("MQ=="); + QTest::newRow("3") << QByteArray("12") << QByteArray("MTI="); + QTest::newRow("4") << QByteArray("123") << QByteArray("MTIz"); + QTest::newRow("5") << QByteArray("1234") << QByteArray("MTIzNA=="); + QTest::newRow("6") << QByteArray("\n") << QByteArray("Cg=="); + QTest::newRow("7") << QByteArray("a\n") << QByteArray("YQo="); + QTest::newRow("8") << QByteArray("ab\n") << QByteArray("YWIK"); + QTest::newRow("9") << QByteArray("abc\n") << QByteArray("YWJjCg=="); + QTest::newRow("a") << QByteArray("abcd\n") << QByteArray("YWJjZAo="); + QTest::newRow("b") << QByteArray("abcde\n") << QByteArray("YWJjZGUK"); + QTest::newRow("c") << QByteArray("abcdef\n") << QByteArray("YWJjZGVmCg=="); + QTest::newRow("d") << QByteArray("abcdefg\n") << QByteArray("YWJjZGVmZwo="); + QTest::newRow("e") << QByteArray("abcdefgh\n") << QByteArray("YWJjZGVmZ2gK"); + + QByteArray ba; + ba.resize(256); + for (int i = 0; i < 256; ++i) + ba[i] = i; + QTest::newRow("f") << ba << QByteArray("AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/w=="); + + QTest::newRow("g") << QByteArray("foo\0bar", 7) << QByteArray("Zm9vAGJhcg=="); + QTest::newRow("h") << QByteArray("f\xd1oo\x9ctar") << QByteArray("ZtFvb5x0YXI="); + QTest::newRow("i") << QByteArray("\"\0\0\0\0\0\0\"", 8) << QByteArray("IgAAAAAAACI="); +} + + +void tst_QByteArray::base64() +{ + QFETCH(QByteArray, rawdata); + QFETCH(QByteArray, base64); + + QByteArray arr = QByteArray::fromBase64(base64); + QCOMPARE(arr, rawdata); + + QByteArray arr64 = rawdata.toBase64(); + QCOMPARE(arr64, base64); + + arr64 = rawdata.toBase64(QByteArray::Base64Encoding); + QCOMPARE(arr64, base64); + + QByteArray base64noequals = base64; + base64noequals.replace('=', ""); + arr64 = rawdata.toBase64(QByteArray::Base64Encoding | QByteArray::OmitTrailingEquals); + QCOMPARE(arr64, base64noequals); + + QByteArray base64url = base64; + base64url.replace('/', '_').replace('+', '-'); + arr64 = rawdata.toBase64(QByteArray::Base64UrlEncoding); + QCOMPARE(arr64, base64url); + + QByteArray base64urlnoequals = base64url; + base64urlnoequals.replace('=', ""); + arr64 = rawdata.toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals); + QCOMPARE(arr64, base64urlnoequals); +} + +//different from the previous test as the input are invalid +void tst_QByteArray::fromBase64_data() +{ + QTest::addColumn("rawdata"); + QTest::addColumn("base64"); + + QTest::newRow("1") << QByteArray("") << QByteArray(" "); + QTest::newRow("2") << QByteArray("1") << QByteArray("MQ"); + QTest::newRow("3") << QByteArray("12") << QByteArray("MTI "); + QTest::newRow("4") << QByteArray("123") << QByteArray("M=TIz"); + QTest::newRow("5") << QByteArray("1234") << QByteArray("MTI zN A "); + QTest::newRow("6") << QByteArray("\n") << QByteArray("Cg"); + QTest::newRow("7") << QByteArray("a\n") << QByteArray("======YQo="); + QTest::newRow("8") << QByteArray("ab\n") << QByteArray("Y\nWIK"); + QTest::newRow("9") << QByteArray("abc\n") << QByteArray("YWJjCg=="); + QTest::newRow("a") << QByteArray("abcd\n") << QByteArray("YWJ\1j\x9cZAo="); + QTest::newRow("b") << QByteArray("abcde\n") << QByteArray("YW JjZ\n G\tUK"); + QTest::newRow("c") << QByteArray("abcdef\n") << QByteArray("YWJjZGVmCg="); + QTest::newRow("d") << QByteArray("abcdefg\n") << QByteArray("YWJ\rjZGVmZwo"); + QTest::newRow("e") << QByteArray("abcdefgh\n") << QByteArray("YWJjZGVmZ2gK"); + + QByteArray ba; + ba.resize(256); + for (int i = 0; i < 256; ++i) + ba[i] = i; + QTest::newRow("f") << ba << QByteArray("AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Nj\n" + "c4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1u\n" + "b3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpa\n" + "anqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd\n" + "3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/w== "); + + + QTest::newRow("g") << QByteArray("foo\0bar", 7) << QByteArray("Zm9vAGJhcg"); + QTest::newRow("h") << QByteArray("f\xd1oo\x9ctar") << QByteArray("ZtFvb5x0YXI="); + QTest::newRow("i") << QByteArray("\"\0\0\0\0\0\0\"", 8) << QByteArray("IgAAAAAAACI"); + +} + + +void tst_QByteArray::fromBase64() +{ + QFETCH(QByteArray, rawdata); + QFETCH(QByteArray, base64); + + QByteArray arr = QByteArray::fromBase64(base64); + QCOMPARE(arr, rawdata); + + arr = QByteArray::fromBase64(base64, QByteArray::Base64Encoding); + QCOMPARE(arr, rawdata); + + // try "base64url" encoding + QByteArray base64url = base64; + base64url.replace('/', '_').replace('+', '-'); + arr = QByteArray::fromBase64(base64url, QByteArray::Base64UrlEncoding); + QCOMPARE(arr, rawdata); + + if (base64 != base64url) { + // check that the invalid decodings fail + arr = QByteArray::fromBase64(base64, QByteArray::Base64UrlEncoding); + QVERIFY(arr != rawdata); + arr = QByteArray::fromBase64(base64url, QByteArray::Base64Encoding); + QVERIFY(arr != rawdata); + } +} + +void tst_QByteArray::qvsnprintf() +{ + char buf[20]; + memset(buf, 42, sizeof(buf)); + + QCOMPARE(::qsnprintf(buf, 10, "%s", "bubu"), 4); + QCOMPARE(static_cast(buf), "bubu"); +#ifndef Q_CC_MSVC + // MSVC implementation of vsnprintf overwrites bytes after null terminator so this would fail. + QCOMPARE(buf[5], char(42)); +#endif + + memset(buf, 42, sizeof(buf)); + QCOMPARE(::qsnprintf(buf, 5, "%s", "bubu"), 4); + QCOMPARE(static_cast(buf), "bubu"); + QCOMPARE(buf[5], char(42)); + + memset(buf, 42, sizeof(buf)); +#ifdef Q_OS_WIN + // VS 2005 uses the Qt implementation of vsnprintf. +# if defined(_MSC_VER) + QCOMPARE(::qsnprintf(buf, 3, "%s", "bubu"), -1); + QCOMPARE(static_cast(buf), "bu"); +# else + // windows has to do everything different, of course. + QCOMPARE(::qsnprintf(buf, 3, "%s", "bubu"), -1); + buf[19] = '\0'; + QCOMPARE(static_cast(buf), "bub****************"); +# endif +#else + QCOMPARE(::qsnprintf(buf, 3, "%s", "bubu"), 4); + QCOMPARE(static_cast(buf), "bu"); +#endif + QCOMPARE(buf[4], char(42)); + +#ifndef Q_OS_WIN + memset(buf, 42, sizeof(buf)); + QCOMPARE(::qsnprintf(buf, 10, ""), 0); +#endif +} + + +void tst_QByteArray::qstrlen() +{ + const char *src = "Something about ... \0 a string."; + QCOMPARE(::qstrlen((char*)0), (uint)0); + QCOMPARE(::qstrlen(src), (uint)20); +} + +void tst_QByteArray::qstrnlen() +{ + const char *src = "Something about ... \0 a string."; + QCOMPARE(::qstrnlen((char*)0, 1), (uint)0); + QCOMPARE(::qstrnlen(src, 31), (uint)20); + QCOMPARE(::qstrnlen(src, 19), (uint)19); + QCOMPARE(::qstrnlen(src, 21), (uint)20); + QCOMPARE(::qstrnlen(src, 20), (uint)20); +} + +void tst_QByteArray::qstrcpy() +{ + const char *src = "Something about ... \0 a string."; + const char *expected = "Something about ... "; + char dst[128]; + + QCOMPARE(::qstrcpy(0, 0), (char*)0); + QCOMPARE(::qstrcpy(dst, 0), (char*)0); + + QCOMPARE(::qstrcpy(dst ,src), (char *)dst); + QCOMPARE((char *)dst, const_cast(expected)); +} + +void tst_QByteArray::qstrncpy() +{ + QByteArray src(1024, 'a'), dst(1024, 'b'); + + // dst == nullptr + QCOMPARE(::qstrncpy(0, src.data(), 0), (char*)0); + QCOMPARE(::qstrncpy(0, src.data(), 10), (char*)0); + + // src == nullptr + QCOMPARE(::qstrncpy(dst.data(), 0, 0), (char*)0); + QCOMPARE(::qstrncpy(dst.data(), 0, 10), (char*)0); + + // valid pointers, but len == 0 + QCOMPARE(::qstrncpy(dst.data(), src.data(), 0), dst.data()); + QCOMPARE(*dst.data(), 'b'); // must not have written to dst + + // normal copy + QCOMPARE(::qstrncpy(dst.data(), src.data(), src.size()), dst.data()); + + src = QByteArray( "Tumdelidum" ); + QCOMPARE(QByteArray(::qstrncpy(dst.data(), src.data(), src.size())), + QByteArray("Tumdelidu")); + + // normal copy with length is longer than necessary + src = QByteArray( "Tumdelidum\0foo" ); + dst.resize(128*1024); + QCOMPARE(QByteArray(::qstrncpy(dst.data(), src.data(), dst.size())), + QByteArray("Tumdelidum")); +} + +void tst_QByteArray::qstricmp_data() +{ + QTest::addColumn("str1"); + QTest::addColumn("str2"); + + QTest::newRow("equal 1") << "abcEdb" << "abcEdb"; + QTest::newRow("equal 2") << "abcEdb" << "ABCeDB"; + QTest::newRow("equal 3") << "ABCEDB" << "abcedb"; + QTest::newRow("less 1") << "abcdef" << "abcdefg"; + QTest::newRow("less 2") << "abcdeF" << "abcdef"; + QTest::newRow("greater 1") << "abcdef" << "abcdeF"; + QTest::newRow("greater 2") << "abcdefg" << "abcdef"; +} + +void tst_QByteArray::qstricmp() +{ + QFETCH(QString, str1); + QFETCH(QString, str2); + + int expected = strcmp(str1.toUpper().toLatin1(), + str2.toUpper().toLatin1()); + if ( expected != 0 ) { + expected = (expected < 0 ? -1 : 1); + } + int actual = ::qstricmp(str1.toLatin1(), str2.toLatin1()); + if ( actual != 0 ) { + actual = (actual < 0 ? -1 : 1); + } + QCOMPARE(actual, expected); + + actual = ::qstricmp("012345679abcd" + str1.toLatin1(), "012345679AbCd" + str2.toLatin1()); + if ( actual != 0 ) { + actual = (actual < 0 ? -1 : 1); + } + QCOMPARE(actual, expected); + + actual = str1.toLatin1().compare(str2.toLatin1(), Qt::CaseInsensitive); + if ( actual != 0 ) { + actual = (actual < 0 ? -1 : 1); + } + QCOMPARE(actual, expected); + + actual = str1.toLatin1().compare(str2.toLatin1().constData(), Qt::CaseInsensitive); + if ( actual != 0 ) { + actual = (actual < 0 ? -1 : 1); + } + QCOMPARE(actual, expected); +} + +void tst_QByteArray::qstricmp_singularities() +{ + QCOMPARE(::qstricmp(0, 0), 0); + QVERIFY(::qstricmp(0, "a") < 0); + QVERIFY(::qstricmp("a", 0) > 0); + QCOMPARE(::qstricmp("", ""), 0); + QCOMPARE(QByteArray().compare(nullptr, Qt::CaseInsensitive), 0); + QCOMPARE(QByteArray().compare("", Qt::CaseInsensitive), 0); + QVERIFY(QByteArray("a").compare(nullptr, Qt::CaseInsensitive) > 0); + QVERIFY(QByteArray("a").compare("", Qt::CaseInsensitive) > 0); + QVERIFY(QByteArray().compare("a", Qt::CaseInsensitive) < 0); +} + +void tst_QByteArray::qstrnicmp_singularities() +{ + QCOMPARE(::qstrnicmp(0, 0, 123), 0); + QVERIFY(::qstrnicmp(0, "a", 123) != 0); + QVERIFY(::qstrnicmp("a", 0, 123) != 0); + QCOMPARE(::qstrnicmp("", "", 123), 0); + QCOMPARE(::qstrnicmp("a", "B", 0), 0); + QCOMPARE(QByteArray().compare(QByteArray(), Qt::CaseInsensitive), 0); + QVERIFY(QByteArray().compare(QByteArray("a"), Qt::CaseInsensitive) < 0); + QVERIFY(QByteArray("a").compare(QByteArray(), Qt::CaseInsensitive) > 0); +} + +void tst_QByteArray::chop_data() +{ + QTest::addColumn("src"); + QTest::addColumn("choplength"); + QTest::addColumn("expected"); + + QTest::newRow("1") << QByteArray("short1") << 128 << QByteArray(); + QTest::newRow("2") << QByteArray("short2") << int(strlen("short2")) + << QByteArray(); + QTest::newRow("3") << QByteArray("abcdef\0foo", 10) << 2 + << QByteArray("abcdef\0f", 8); + QTest::newRow("4") << QByteArray("STARTTLS\r\n") << 2 + << QByteArray("STARTTLS"); + QTest::newRow("5") << QByteArray("") << 1 << QByteArray(); + QTest::newRow("6") << QByteArray("foo") << 0 << QByteArray("foo"); + QTest::newRow("7") << QByteArray(0) << 28 << QByteArray(); +} + +void tst_QByteArray::chop() +{ + QFETCH(QByteArray, src); + QFETCH(int, choplength); + QFETCH(QByteArray, expected); + + src.chop(choplength); + QCOMPARE(src, expected); +} + +void tst_QByteArray::prepend() +{ + QByteArray ba("foo"); + QCOMPARE(ba.prepend((char*)0), QByteArray("foo")); + QCOMPARE(ba.prepend(QByteArray()), QByteArray("foo")); + QCOMPARE(ba.prepend("1"), QByteArray("1foo")); + QCOMPARE(ba.prepend(QByteArray("2")), QByteArray("21foo")); + QCOMPARE(ba.prepend('3'), QByteArray("321foo")); + QCOMPARE(ba.prepend(-1, 'x'), QByteArray("321foo")); + QCOMPARE(ba.prepend(3, 'x'), QByteArray("xxx321foo")); + QCOMPARE(ba.prepend("\0 ", 2), QByteArray::fromRawData("\0 xxx321foo", 11)); +} + +void tst_QByteArray::prependExtended_data() +{ + QTest::addColumn("array"); + QTest::newRow("literal") << QByteArray(QByteArrayLiteral("data")); + QTest::newRow("standard") << QByteArray(staticStandard); + QTest::newRow("shifted") << QByteArray(staticShifted); + QTest::newRow("notNullTerminated") << QByteArray(staticNotNullTerminated); + QTest::newRow("shiftedNotNullTerminated") << QByteArray(staticShiftedNotNullTerminated); + QTest::newRow("non static data") << QByteArray("data"); + QTest::newRow("from raw data") << QByteArray::fromRawData("data", 4); + QTest::newRow("from raw data not terminated") << QByteArray::fromRawData("dataBAD", 4); +} + +void tst_QByteArray::prependExtended() +{ + QFETCH(QByteArray, array); + + QCOMPARE(QByteArray().prepend(array), QByteArray("data")); + QCOMPARE(QByteArray("").prepend(array), QByteArray("data")); + + QCOMPARE(array.prepend((char*)0), QByteArray("data")); + QCOMPARE(array.prepend(QByteArray()), QByteArray("data")); + QCOMPARE(array.prepend("1"), QByteArray("1data")); + QCOMPARE(array.prepend(QByteArray("2")), QByteArray("21data")); + QCOMPARE(array.prepend('3'), QByteArray("321data")); + QCOMPARE(array.prepend(-1, 'x'), QByteArray("321data")); + QCOMPARE(array.prepend(3, 'x'), QByteArray("xxx321data")); + QCOMPARE(array.prepend("\0 ", 2), QByteArray::fromRawData("\0 xxx321data", 12)); + QCOMPARE(array.size(), 12); +} + +void tst_QByteArray::append() +{ + QByteArray ba("foo"); + QCOMPARE(ba.append((char*)0), QByteArray("foo")); + QCOMPARE(ba.append(QByteArray()), QByteArray("foo")); + QCOMPARE(ba.append("1"), QByteArray("foo1")); + QCOMPARE(ba.append(QByteArray("2")), QByteArray("foo12")); + QCOMPARE(ba.append('3'), QByteArray("foo123")); + QCOMPARE(ba.append(-1, 'x'), QByteArray("foo123")); + QCOMPARE(ba.append(3, 'x'), QByteArray("foo123xxx")); + QCOMPARE(ba.append("\0"), QByteArray("foo123xxx")); + QCOMPARE(ba.append("\0", 1), QByteArray::fromRawData("foo123xxx\0", 10)); + QCOMPARE(ba.size(), 10); +} + +void tst_QByteArray::appendExtended_data() +{ + prependExtended_data(); +} + +void tst_QByteArray::appendExtended() +{ + QFETCH(QByteArray, array); + + QCOMPARE(QByteArray().append(array), QByteArray("data")); + QCOMPARE(QByteArray("").append(array), QByteArray("data")); + + QCOMPARE(array.append((char*)0), QByteArray("data")); + QCOMPARE(array.append(QByteArray()), QByteArray("data")); + QCOMPARE(array.append("1"), QByteArray("data1")); + QCOMPARE(array.append(QByteArray("2")), QByteArray("data12")); + QCOMPARE(array.append('3'), QByteArray("data123")); + QCOMPARE(array.append(-1, 'x'), QByteArray("data123")); + QCOMPARE(array.append(3, 'x'), QByteArray("data123xxx")); + QCOMPARE(array.append("\0"), QByteArray("data123xxx")); + QCOMPARE(array.append("\0", 1), QByteArray::fromRawData("data123xxx\0", 11)); + QCOMPARE(array.size(), 11); +} + +void tst_QByteArray::insert() +{ + QByteArray ba("Meal"); + QCOMPARE(ba.insert(1, QByteArray("ontr")), QByteArray("Montreal")); + QCOMPARE(ba.insert(ba.size(), "foo"), QByteArray("Montrealfoo")); + + ba = QByteArray("13"); + QCOMPARE(ba.insert(1, QByteArray("2")), QByteArray("123")); + + ba = "ac"; + QCOMPARE(ba.insert(1, 'b'), QByteArray("abc")); + QCOMPARE(ba.size(), 3); + + ba = "ac"; + QCOMPARE(ba.insert(-1, 3, 'x'), QByteArray("ac")); + QCOMPARE(ba.insert(1, 3, 'x'), QByteArray("axxxc")); + QCOMPARE(ba.insert(6, 3, 'x'), QByteArray("axxxc xxx")); + QCOMPARE(ba.size(), 9); + + ba = "ikl"; + QCOMPARE(ba.insert(1, "j"), QByteArray("ijkl")); + QCOMPARE(ba.size(), 4); + + ba = "ab"; + QCOMPARE(ba.insert(1, "\0X\0", 3), QByteArray::fromRawData("a\0X\0b", 5)); + QCOMPARE(ba.size(), 5); +} + +void tst_QByteArray::insertExtended_data() +{ + prependExtended_data(); +} + +void tst_QByteArray::insertExtended() +{ + QFETCH(QByteArray, array); + QCOMPARE(array.insert(1, "i"), QByteArray("diata")); + QCOMPARE(array.insert(1, 3, 'x'), QByteArray("dxxxiata")); + QCOMPARE(array.size(), 8); +} + +void tst_QByteArray::remove_data() +{ + QTest::addColumn("src"); + QTest::addColumn("position"); + QTest::addColumn("length"); + QTest::addColumn("expected"); + + QTest::newRow("1") << QByteArray("Montreal") << 1 << 4 + << QByteArray("Meal"); + QTest::newRow("2") << QByteArray() << 10 << 10 << QByteArray(); + QTest::newRow("3") << QByteArray("hi") << 0 << 10 << QByteArray(); + QTest::newRow("4") << QByteArray("Montreal") << 4 << 100 + << QByteArray("Mont"); + + // index out of range + QTest::newRow("5") << QByteArray("Montreal") << 8 << 1 + << QByteArray("Montreal"); + QTest::newRow("6") << QByteArray("Montreal") << 18 << 4 + << QByteArray("Montreal"); +} + +void tst_QByteArray::remove() +{ + QFETCH(QByteArray, src); + QFETCH(int, position); + QFETCH(int, length); + QFETCH(QByteArray, expected); + QCOMPARE(src.remove(position, length), expected); +} + +void tst_QByteArray::replace_data() +{ + QTest::addColumn("src"); + QTest::addColumn("pos"); + QTest::addColumn("len"); + QTest::addColumn("after"); + QTest::addColumn("expected"); + + QTest::newRow("1") << QByteArray("Say yes!") << 4 << 3 + << QByteArray("no") << QByteArray("Say no!"); + QTest::newRow("2") << QByteArray("rock and roll") << 5 << 3 + << QByteArray("&") << QByteArray("rock & roll"); + QTest::newRow("3") << QByteArray("foo") << 3 << 0 << QByteArray("bar") + << QByteArray("foobar"); + QTest::newRow("4") << QByteArray() << 0 << 0 << QByteArray() << QByteArray(); + // index out of range + QTest::newRow("5") << QByteArray() << 3 << 0 << QByteArray("hi") + << QByteArray(" hi"); + // Optimized path + QTest::newRow("6") << QByteArray("abcdef") << 3 << 12 << QByteArray("abcdefghijkl") << QByteArray("abcabcdefghijkl"); + QTest::newRow("7") << QByteArray("abcdef") << 3 << 4 << QByteArray("abcdefghijkl") << QByteArray("abcabcdefghijkl"); + QTest::newRow("8") << QByteArray("abcdef") << 3 << 3 << QByteArray("abcdefghijkl") << QByteArray("abcabcdefghijkl"); + QTest::newRow("9") << QByteArray("abcdef") << 3 << 2 << QByteArray("abcdefghijkl") << QByteArray("abcabcdefghijklf"); + QTest::newRow("10") << QByteArray("abcdef") << 2 << 2 << QByteArray("xx") << QByteArray("abxxef"); +} + +void tst_QByteArray::replace() +{ + QFETCH(QByteArray, src); + QFETCH(int, pos); + QFETCH(int, len); + QFETCH(QByteArray, after); + QFETCH(QByteArray, expected); + + QByteArray str1 = src; + QByteArray str2 = src; + + QCOMPARE(str1.replace(pos, len, after).constData(), expected.constData()); + QCOMPARE(str2.replace(pos, len, after.data()), expected); +} + +void tst_QByteArray::replaceWithSpecifiedLength() +{ + const char after[] = "zxc\0vbnmqwert"; + int lenAfter = 6; + QByteArray ba("abcdefghjk"); + ba.replace(0,2,after,lenAfter); + + const char _expected[] = "zxc\0vbcdefghjk"; + QByteArray expected(_expected,sizeof(_expected)-1); + QCOMPARE(ba,expected); +} + +void tst_QByteArray::indexOf_data() +{ + QTest::addColumn("haystack"); + QTest::addColumn("needle"); + QTest::addColumn("startpos"); + QTest::addColumn("expected"); + + QTest::newRow( "1" ) << QByteArray("abc") << QByteArray("a") << 0 << 0; + QTest::newRow( "2" ) << QByteArray("abc") << QByteArray("A") << 0 << -1; + QTest::newRow( "3" ) << QByteArray("abc") << QByteArray("a") << 1 << -1; + QTest::newRow( "4" ) << QByteArray("abc") << QByteArray("A") << 1 << -1; + QTest::newRow( "5" ) << QByteArray("abc") << QByteArray("b") << 0 << 1; + QTest::newRow( "6" ) << QByteArray("abc") << QByteArray("B") << 0 << -1; + QTest::newRow( "7" ) << QByteArray("abc") << QByteArray("b") << 1 << 1; + QTest::newRow( "8" ) << QByteArray("abc") << QByteArray("B") << 1 << -1; + QTest::newRow( "9" ) << QByteArray("abc") << QByteArray("b") << 2 << -1; + QTest::newRow( "10" ) << QByteArray("abc") << QByteArray("c") << 0 << 2; + QTest::newRow( "11" ) << QByteArray("abc") << QByteArray("C") << 0 << -1; + QTest::newRow( "12" ) << QByteArray("abc") << QByteArray("c") << 1 << 2; + QTest::newRow( "13" ) << QByteArray("abc") << QByteArray("C") << 1 << -1; + QTest::newRow( "14" ) << QByteArray("abc") << QByteArray("c") << 2 << 2; + QTest::newRow( "15" ) << QByteArray("aBc") << QByteArray("bc") << 0 << -1; + QTest::newRow( "16" ) << QByteArray("aBc") << QByteArray("Bc") << 0 << 1; + QTest::newRow( "17" ) << QByteArray("aBc") << QByteArray("bC") << 0 << -1; + QTest::newRow( "18" ) << QByteArray("aBc") << QByteArray("BC") << 0 << -1; + + static const char h19[] = {'x', 0x00, (char)0xe7, 0x25, 0x1c, 0x0a}; + static const char n19[] = {0x00, 0x00, 0x01, 0x00}; + QTest::newRow( "19" ) << QByteArray(h19, sizeof(h19)) + << QByteArray(n19, sizeof(n19)) << 0 << -1; + + QTest::newRow( "empty" ) << QByteArray("") << QByteArray("x") << 0 << -1; + QTest::newRow( "null" ) << QByteArray() << QByteArray("x") << 0 << -1; + QTest::newRow( "null-in-null") << QByteArray() << QByteArray() << 0 << 0; + QTest::newRow( "empty-in-null") << QByteArray() << QByteArray("") << 0 << 0; + QTest::newRow( "null-in-empty") << QByteArray("") << QByteArray() << 0 << 0; + QTest::newRow( "empty-in-empty") << QByteArray("") << QByteArray("") << 0 << 0; + + QByteArray veryBigHaystack(500, 'a'); + veryBigHaystack += 'B'; + QTest::newRow("BoyerMooreStressTest") << veryBigHaystack << veryBigHaystack << 0 << 0; + QTest::newRow("BoyerMooreStressTest2") << QByteArray(veryBigHaystack + 'c') << QByteArray(veryBigHaystack) << 0 << 0; + QTest::newRow("BoyerMooreStressTest3") << QByteArray('c' + veryBigHaystack) << QByteArray(veryBigHaystack) << 0 << 1; + QTest::newRow("BoyerMooreStressTest4") << QByteArray(veryBigHaystack) << QByteArray(veryBigHaystack + 'c') << 0 << -1; + QTest::newRow("BoyerMooreStressTest5") << QByteArray(veryBigHaystack) << QByteArray('c' + veryBigHaystack) << 0 << -1; + QTest::newRow("BoyerMooreStressTest6") << QByteArray('d' + veryBigHaystack) << QByteArray('c' + veryBigHaystack) << 0 << -1; + QTest::newRow("BoyerMooreStressTest7") << QByteArray(veryBigHaystack + 'c') << QByteArray('c' + veryBigHaystack) << 0 << -1; +} + +void tst_QByteArray::indexOf() +{ + QFETCH( QByteArray, haystack ); + QFETCH( QByteArray, needle ); + QFETCH( int, startpos ); + QFETCH( int, expected ); + + bool hasNull = needle.contains('\0'); + + QCOMPARE( haystack.indexOf(needle, startpos), expected ); + if (!hasNull) + QCOMPARE( haystack.indexOf(needle.data(), startpos), expected ); + if (needle.size() == 1) + QCOMPARE( haystack.indexOf(needle.at(0), startpos), expected ); + + if (startpos == 0) { + QCOMPARE( haystack.indexOf(needle), expected ); + if (!hasNull) + QCOMPARE( haystack.indexOf(needle.data()), expected ); + if (needle.size() == 1) + QCOMPARE( haystack.indexOf(needle.at(0)), expected ); + } +} + +void tst_QByteArray::lastIndexOf_data() +{ + QTest::addColumn("haystack"); + QTest::addColumn("needle"); + QTest::addColumn("startpos"); + QTest::addColumn("expected"); + + QTest::newRow( "1" ) << QByteArray("abc") << QByteArray("a") << 0 << 0; + QTest::newRow( "2" ) << QByteArray("abc") << QByteArray("A") << 0 << -1; + QTest::newRow( "3" ) << QByteArray("abc") << QByteArray("a") << 1 << 0; + QTest::newRow( "4" ) << QByteArray("abc") << QByteArray("A") << 1 << -1; + QTest::newRow( "5" ) << QByteArray("abc") << QByteArray("a") << -1 << 0; + QTest::newRow( "6" ) << QByteArray("abc") << QByteArray("b") << 0 << -1; + QTest::newRow( "7" ) << QByteArray("abc") << QByteArray("B") << 0 << -1; + QTest::newRow( "8" ) << QByteArray("abc") << QByteArray("b") << 1 << 1; + QTest::newRow( "9" ) << QByteArray("abc") << QByteArray("B") << 1 << -1; + QTest::newRow( "10" ) << QByteArray("abc") << QByteArray("b") << 2 << 1; + QTest::newRow( "11" ) << QByteArray("abc") << QByteArray("b") << -1 << 1; + QTest::newRow( "12" ) << QByteArray("abc") << QByteArray("c") << 0 << -1; + QTest::newRow( "13" ) << QByteArray("abc") << QByteArray("C") << 0 << -1; + QTest::newRow( "14" ) << QByteArray("abc") << QByteArray("c") << 1 << -1; + QTest::newRow( "15" ) << QByteArray("abc") << QByteArray("C") << 1 << -1; + QTest::newRow( "16" ) << QByteArray("abc") << QByteArray("c") << 2 << 2; + QTest::newRow( "17" ) << QByteArray("abc") << QByteArray("c") << -1 << 2; + QTest::newRow( "18" ) << QByteArray("aBc") << QByteArray("bc") << 0 << -1; + QTest::newRow( "19" ) << QByteArray("aBc") << QByteArray("Bc") << 0 << -1; + QTest::newRow( "20" ) << QByteArray("aBc") << QByteArray("Bc") << 2 << 1; + QTest::newRow( "21" ) << QByteArray("aBc") << QByteArray("Bc") << 1 << 1; + QTest::newRow( "22" ) << QByteArray("aBc") << QByteArray("Bc") << -1 << 1; + QTest::newRow( "23" ) << QByteArray("aBc") << QByteArray("bC") << 0 << -1; + QTest::newRow( "24" ) << QByteArray("aBc") << QByteArray("BC") << 0 << -1; + + static const char h25[] = {0x00, (char)0xbc, 0x03, 0x10, 0x0a }; + static const char n25[] = {0x00, 0x00, 0x01, 0x00}; + QTest::newRow( "25" ) << QByteArray(h25, sizeof(h25)) + << QByteArray(n25, sizeof(n25)) << 0 << -1; + + QTest::newRow( "empty" ) << QByteArray("") << QByteArray("x") << -1 << -1; + QTest::newRow( "null" ) << QByteArray() << QByteArray("x") << -1 << -1; + QTest::newRow( "null-in-null") << QByteArray() << QByteArray() << -1 << 0; + QTest::newRow( "empty-in-null") << QByteArray() << QByteArray("") << -1 << 0; + QTest::newRow( "null-in-empty") << QByteArray("") << QByteArray() << -1 << 0; + QTest::newRow( "empty-in-empty") << QByteArray("") << QByteArray("") << -1 << 0; +} + +void tst_QByteArray::lastIndexOf() +{ + QFETCH( QByteArray, haystack ); + QFETCH( QByteArray, needle ); + QFETCH( int, startpos ); + QFETCH( int, expected ); + + bool hasNull = needle.contains('\0'); + + QCOMPARE( haystack.lastIndexOf(needle, startpos), expected ); + if (!hasNull) + QCOMPARE( haystack.lastIndexOf(needle.data(), startpos), expected ); + if (needle.size() == 1) + QCOMPARE( haystack.lastIndexOf(needle.at(0), startpos), expected ); + + if (startpos == -1) { + QCOMPARE( haystack.lastIndexOf(needle), expected ); + if (!hasNull) + QCOMPARE( haystack.lastIndexOf(needle.data()), expected ); + if (needle.size() == 1) + QCOMPARE( haystack.lastIndexOf(needle.at(0)), expected ); + } +} + +void tst_QByteArray::number() +{ + QCOMPARE(QString(QByteArray::number((quint64) 0)), + QString(QByteArray("0"))); + QCOMPARE(QString(QByteArray::number(Q_UINT64_C(0xFFFFFFFFFFFFFFFF))), + QString(QByteArray("18446744073709551615"))); + QCOMPARE(QString(QByteArray::number(Q_INT64_C(0xFFFFFFFFFFFFFFFF))), + QString(QByteArray("-1"))); + QCOMPARE(QString(QByteArray::number(qint64(0))), + QString(QByteArray("0"))); + QCOMPARE(QString(QByteArray::number(Q_INT64_C(0x7FFFFFFFFFFFFFFF))), + QString(QByteArray("9223372036854775807"))); + QCOMPARE(QString(QByteArray::number(Q_INT64_C(0x8000000000000000))), + QString(QByteArray("-9223372036854775808"))); +} + +// defined later +extern const char globalChar; + +void tst_QByteArray::toInt_data() +{ + QTest::addColumn("string"); + QTest::addColumn("base"); + QTest::addColumn("expectednumber"); + QTest::addColumn("expectedok"); + + QTest::newRow("base 10") << QByteArray("100") << 10 << int(100) << true; + QTest::newRow("base 16-1") << QByteArray("100") << 16 << int(256) << true; + QTest::newRow("base 16-2") << QByteArray("0400") << 16 << int(1024) << true; + QTest::newRow("base 2") << QByteArray("1111") << 2 << int(15) << true; + QTest::newRow("base 8") << QByteArray("100") << 8 << int(64) << true; + QTest::newRow("base 0-1") << QByteArray("0x10") << 0 << int(16) << true; + QTest::newRow("base 0-2") << QByteArray("10") << 0 << int(10) << true; + QTest::newRow("base 0-3") << QByteArray("010") << 0 << int(8) << true; + QTest::newRow("empty") << QByteArray() << 0 << int(0) << false; + + QTest::newRow("leading space") << QByteArray(" 100") << 10 << int(100) << true; + QTest::newRow("trailing space") << QByteArray("100 ") << 10 << int(100) << true; + QTest::newRow("leading junk") << QByteArray("x100") << 10 << int(0) << false; + QTest::newRow("trailing junk") << QByteArray("100x") << 10 << int(0) << false; + + // using fromRawData + QTest::newRow("raw1") << QByteArray::fromRawData("1", 1) << 10 << 1 << true; + QTest::newRow("raw2") << QByteArray::fromRawData("1foo", 1) << 10 << 1 << true; + QTest::newRow("raw3") << QByteArray::fromRawData("12", 1) << 10 << 1 << true; + QTest::newRow("raw4") << QByteArray::fromRawData("123456789", 1) << 10 << 1 << true; + QTest::newRow("raw5") << QByteArray::fromRawData("123456789", 2) << 10 << 12 << true; + + QTest::newRow("raw-static") << QByteArray::fromRawData(&globalChar, 1) << 10 << 1 << true; +} + +void tst_QByteArray::toInt() +{ + QFETCH( QByteArray, string ); + QFETCH( int, base ); + QFETCH( int, expectednumber ); + QFETCH( bool, expectedok ); + + bool ok; + int number = string.toInt(&ok, base); + + QCOMPARE( ok, expectedok ); + QCOMPARE( number, expectednumber ); +} + +void tst_QByteArray::toDouble_data() +{ + QTest::addColumn("string"); + QTest::addColumn("expectedNumber"); + QTest::addColumn("expectedOk"); + + QTest::newRow("decimal") << QByteArray("1.2345") << 1.2345 << true; + QTest::newRow("exponent lowercase") << QByteArray("1.2345e+01") << 12.345 << true; + QTest::newRow("exponent uppercase") << QByteArray("1.2345E+02") << 123.45 << true; + QTest::newRow("leading spaces") << QByteArray(" \n\r\t1.2345") << 1.2345 << true; + QTest::newRow("trailing spaces") << QByteArray("1.2345 \n\r\t") << 1.2345 << true; + QTest::newRow("leading junk") << QByteArray("x1.2345") << 0.0 << false; + QTest::newRow("trailing junk") << QByteArray("1.2345x") << 0.0 << false; + + QTest::newRow("raw, null plus junk") << QByteArray::fromRawData("1.2\0 junk", 9) << 0.0 << false; + QTest::newRow("raw, null-terminator not included") << QByteArray::fromRawData("2.3", 3) << 2.3 << true; +} + +void tst_QByteArray::toDouble() +{ + QFETCH(QByteArray, string); + QFETCH(double, expectedNumber); + QFETCH(bool, expectedOk); + + bool ok; + const double number = string.toDouble(&ok); + + QCOMPARE(ok, expectedOk); + QCOMPARE(number, expectedNumber); +} + +void tst_QByteArray::toULong_data() +{ + QTest::addColumn("str"); + QTest::addColumn("base"); + QTest::addColumn("result"); + QTest::addColumn("ok"); + + ulong LongMaxPlusOne = (ulong)LONG_MAX + 1; + QTest::newRow("LONG_MAX+1") << QString::number(LongMaxPlusOne).toLatin1() << 10 << LongMaxPlusOne << true; + QTest::newRow("default") << QByteArray() << 10 << 0UL << false; + QTest::newRow("empty") << QByteArray("") << 10 << 0UL << false; + QTest::newRow("ulong1") << QByteArray("3234567890") << 10 << 3234567890UL << true; + QTest::newRow("ulong2") << QByteArray("fFFfFfFf") << 16 << 0xFFFFFFFFUL << true; + + QTest::newRow("leading spaces") << QByteArray(" \n\r\t100") << 10 << 100UL << true; + QTest::newRow("trailing spaces") << QByteArray("100 \n\r\t") << 10 << 100UL << true; + QTest::newRow("leading junk") << QByteArray("x100") << 10 << 0UL << false; + QTest::newRow("trailing junk") << QByteArray("100x") << 10 << 0UL << false; +} + +void tst_QByteArray::toULong() +{ + QFETCH(QByteArray, str); + QFETCH(int, base); + QFETCH(ulong, result); + QFETCH(bool, ok); + + bool b; + QCOMPARE(str.toULong(0, base), result); + QCOMPARE(str.toULong(&b, base), result); + QCOMPARE(b, ok); +} + +void tst_QByteArray::toULongLong_data() +{ + QTest::addColumn("str"); + QTest::addColumn("base"); + QTest::addColumn("result"); + QTest::addColumn("ok"); + + QTest::newRow("default") << QByteArray() << 10 << (qulonglong)0 << false; + QTest::newRow("out of base bound") << QByteArray("c") << 10 << (qulonglong)0 << false; + + QTest::newRow("leading spaces") << QByteArray(" \n\r\t100") << 10 << qulonglong(100) << true; + QTest::newRow("trailing spaces") << QByteArray("100 \n\r\t") << 10 << qulonglong(100) << true; + QTest::newRow("leading junk") << QByteArray("x100") << 10 << qulonglong(0) << false; + QTest::newRow("trailing junk") << QByteArray("100x") << 10 << qulonglong(0) << false; +} + +void tst_QByteArray::toULongLong() +{ + QFETCH(QByteArray, str); + QFETCH(int, base); + QFETCH(qulonglong, result); + QFETCH(bool, ok); + + bool b; + QCOMPARE(str.toULongLong(0, base), result); + QCOMPARE(str.toULongLong(&b, base), result); + QCOMPARE(b, ok); +} + +static bool checkSize(size_t value, size_t min) +{ + return value >= min && value <= INT_MAX; +} + +// global functions defined in qbytearray.cpp +void tst_QByteArray::blockSizeCalculations() +{ + // Not very important, but please behave :-) + QCOMPARE(qCalculateBlockSize(0, 1), size_t(0)); + QVERIFY(qCalculateGrowingBlockSize(0, 1).size <= MaxAllocSize); + QVERIFY(qCalculateGrowingBlockSize(0, 1).elementCount <= MaxAllocSize); + + // boundary condition + QCOMPARE(qCalculateBlockSize(MaxAllocSize, 1), size_t(MaxAllocSize)); + QCOMPARE(qCalculateBlockSize(MaxAllocSize/2, 2), size_t(MaxAllocSize) - 1); + QCOMPARE(qCalculateBlockSize(MaxAllocSize/2, 2, 1), size_t(MaxAllocSize)); + QCOMPARE(qCalculateGrowingBlockSize(MaxAllocSize, 1).size, size_t(MaxAllocSize)); + QCOMPARE(qCalculateGrowingBlockSize(MaxAllocSize, 1).elementCount, size_t(MaxAllocSize)); + QCOMPARE(qCalculateGrowingBlockSize(MaxAllocSize/2, 2, 1).size, size_t(MaxAllocSize)); + QCOMPARE(qCalculateGrowingBlockSize(MaxAllocSize/2, 2, 1).elementCount, size_t(MaxAllocSize)/2); + + // error conditions + QCOMPARE(qCalculateBlockSize(uint(MaxAllocSize) + 1, 1), size_t(~0)); + QCOMPARE(qCalculateBlockSize(size_t(-1), 1), size_t(~0)); + QCOMPARE(qCalculateBlockSize(MaxAllocSize, 1, 1), size_t(~0)); + QCOMPARE(qCalculateBlockSize(MaxAllocSize/2 + 1, 2), size_t(~0)); + QCOMPARE(qCalculateGrowingBlockSize(uint(MaxAllocSize) + 1, 1).size, size_t(~0)); + QCOMPARE(qCalculateGrowingBlockSize(MaxAllocSize/2 + 1, 2).size, size_t(~0)); + + // overflow conditions + // on 32-bit platforms, (1 << 16) * (1 << 16) = (1 << 32) which is zero + QCOMPARE(qCalculateBlockSize(1 << 16, 1 << 16), size_t(~0)); + QCOMPARE(qCalculateBlockSize(MaxAllocSize/4, 16), size_t(~0)); + // on 32-bit platforms, (1 << 30) * 3 + (1 << 30) would overflow to zero + QCOMPARE(qCalculateBlockSize(1U << 30, 3, 1U << 30), size_t(~0)); + + // exact block sizes + for (int i = 1; i < 1 << 31; i <<= 1) { + QCOMPARE(qCalculateBlockSize(0, 1, i), size_t(i)); + QCOMPARE(qCalculateBlockSize(i, 1), size_t(i)); + QCOMPARE(qCalculateBlockSize(i + i/2, 1), size_t(i + i/2)); + } + for (int i = 1; i < 1 << 30; i <<= 1) { + QCOMPARE(qCalculateBlockSize(i, 2), 2 * size_t(i)); + QCOMPARE(qCalculateBlockSize(i, 2, 1), 2 * size_t(i) + 1); + QCOMPARE(qCalculateBlockSize(i, 2, 16), 2 * size_t(i) + 16); + } + + // growing sizes + for (int i = 1; i < 1 << 31; i <<= 1) { + QVERIFY(checkSize(qCalculateGrowingBlockSize(i, 1).size, i)); + QVERIFY(checkSize(qCalculateGrowingBlockSize(i, 1).elementCount, i)); + QVERIFY(checkSize(qCalculateGrowingBlockSize(i, 1, 16).size, i)); + QVERIFY(checkSize(qCalculateGrowingBlockSize(i, 1, 16).elementCount, i)); + QVERIFY(checkSize(qCalculateGrowingBlockSize(i, 1, 24).size, i)); + QVERIFY(checkSize(qCalculateGrowingBlockSize(i, 1, 16).elementCount, i)); + } + + // growth should be limited + for (int elementSize = 1; elementSize < (1<<8); elementSize <<= 1) { + size_t alloc = 1; + forever { + QVERIFY(checkSize(qCalculateGrowingBlockSize(alloc, elementSize).size, alloc * elementSize)); + size_t newAlloc = qCalculateGrowingBlockSize(alloc, elementSize).elementCount; + QVERIFY(checkSize(newAlloc, alloc)); + if (newAlloc == alloc) + break; // no growth, we're at limit + alloc = newAlloc; + } + QVERIFY(checkSize(alloc, size_t(MaxAllocSize) / elementSize)); + + // the next allocation should be invalid + QCOMPARE(qCalculateGrowingBlockSize(alloc + 1, elementSize).size, size_t(~0)); + } +} + +void tst_QByteArray::resizeAfterFromRawData() +{ + QByteArray buffer("hello world"); + + QByteArray array = QByteArray::fromRawData(buffer.constData(), buffer.size()); + QVERIFY(array.constData() == buffer.constData()); + array.resize(5); + QVERIFY(array.constData() == buffer.constData()); +} + +void tst_QByteArray::appendAfterFromRawData() +{ + QByteArray arr; + { + char data[] = "X"; + arr += QByteArray::fromRawData(data, sizeof(data)); + data[0] = 'Y'; + } + QCOMPARE(arr.at(0), 'X'); +} + +void tst_QByteArray::toFromHex_data() +{ + QTest::addColumn("str"); + QTest::addColumn("sep"); + QTest::addColumn("hex"); + QTest::addColumn("hex_alt1"); + + QTest::newRow("Qt is great! (default)") + << QByteArray("Qt is great!") + << '\0' + << QByteArray("517420697320677265617421") + << QByteArray("51 74 20 69 73 20 67 72 65 61 74 21"); + + QTest::newRow("Qt is great! (with space)") + << QByteArray("Qt is great!") + << ' ' + << QByteArray("51 74 20 69 73 20 67 72 65 61 74 21") + << QByteArray("51 74 20 69 73 20 67 72 65 61 74 21"); + + QTest::newRow("Qt is great! (with minus)") + << QByteArray("Qt is great!") + << '-' + << QByteArray("51-74-20-69-73-20-67-72-65-61-74-21") + << QByteArray("51-74-20-69-73-20-67-72-65-61-74-21"); + + QTest::newRow("Qt is so great!") + << QByteArray("Qt is so great!") + << '\0' + << QByteArray("517420697320736f20677265617421") + << QByteArray("51 74 20 69 73 20 73 6f 20 67 72 65 61 74 21"); + + QTest::newRow("default-constructed") + << QByteArray() + << '\0' + << QByteArray() + << QByteArray(); + + QTest::newRow("default-constructed (with space)") + << QByteArray() + << ' ' + << QByteArray() + << QByteArray(); + + QTest::newRow("empty") + << QByteArray("") + << '\0' + << QByteArray("") + << QByteArray(""); + + QTest::newRow("empty (with space)") + << QByteArray("") + << ' ' + << QByteArray("") + << QByteArray(""); + + QTest::newRow("array-of-null") + << QByteArray("\0", 1) + << '\0' + << QByteArray("00") + << QByteArray("0"); + + QTest::newRow("no-leading-zero") + << QByteArray("\xf") + << '\0' + << QByteArray("0f") + << QByteArray("f"); + + QTest::newRow("single-byte") + << QByteArray("\xaf") + << '\0' + << QByteArray("af") + << QByteArray("xaf"); + + QTest::newRow("no-leading-zero") + << QByteArray("\xd\xde\xad\xc0\xde") + << '\0' + << QByteArray("0ddeadc0de") + << QByteArray("ddeadc0de"); + + QTest::newRow("garbage") + << QByteArray("\xC\xde\xeC\xea\xee\xDe\xee\xee") + << '\0' + << QByteArray("0cdeeceaeedeeeee") + << QByteArray("Code less. Create more. Deploy everywhere."); + + QTest::newRow("under-defined-1") + << QByteArray("\x1\x23") + << '\0' + << QByteArray("0123") + << QByteArray("x123"); + + QTest::newRow("under-defined-2") + << QByteArray("\x12\x34") + << '\0' + << QByteArray("1234") + << QByteArray("x1234"); +} + +void tst_QByteArray::toFromHex() +{ + QFETCH(QByteArray, str); + QFETCH(char, sep); + QFETCH(QByteArray, hex); + QFETCH(QByteArray, hex_alt1); + + if (sep == 0) { + const QByteArray th = str.toHex(); + QCOMPARE(th.size(), hex.size()); + QCOMPARE(th, hex); + } + + { + const QByteArray th = str.toHex(sep); + QCOMPARE(th.size(), hex.size()); + QCOMPARE(th, hex); + } + + { + const QByteArray fh = QByteArray::fromHex(hex); + QCOMPARE(fh.size(), str.size()); + QCOMPARE(fh, str); + } + + QCOMPARE(QByteArray::fromHex(hex_alt1), str); +} + +void tst_QByteArray::toFromPercentEncoding() +{ + QByteArray arr("Qt is great!"); + + QByteArray data = arr.toPercentEncoding(); + QCOMPARE(QString(data), QString("Qt%20is%20great%21")); + QCOMPARE(QByteArray::fromPercentEncoding(data), arr); + + data = arr.toPercentEncoding("! ", "Qt"); + QCOMPARE(QString(data), QString("%51%74 is grea%74!")); + QCOMPARE(QByteArray::fromPercentEncoding(data), arr); + + data = arr.toPercentEncoding(QByteArray(), "abcdefghijklmnopqrstuvwxyz", 'Q'); + QCOMPARE(QString(data), QString("Q51Q74Q20Q69Q73Q20Q67Q72Q65Q61Q74Q21")); + QCOMPARE(QByteArray::fromPercentEncoding(data, 'Q'), arr); + + // verify that to/from percent encoding preserves nullity + arr = ""; + QVERIFY(arr.isEmpty()); + QVERIFY(!arr.isNull()); + QVERIFY(arr.toPercentEncoding().isEmpty()); + QVERIFY(!arr.toPercentEncoding().isNull()); + QVERIFY(QByteArray::fromPercentEncoding("").isEmpty()); + QVERIFY(!QByteArray::fromPercentEncoding("").isNull()); + + arr = QByteArray(); + QVERIFY(arr.isEmpty()); + QVERIFY(arr.isNull()); + QVERIFY(arr.toPercentEncoding().isEmpty()); + QVERIFY(arr.toPercentEncoding().isNull()); + QVERIFY(QByteArray::fromPercentEncoding(QByteArray()).isEmpty()); + QVERIFY(QByteArray::fromPercentEncoding(QByteArray()).isNull()); +} + +void tst_QByteArray::fromPercentEncoding_data() +{ + QTest::addColumn("encodedString"); + QTest::addColumn("decodedString"); + + QTest::newRow("NormalString") << QByteArray("filename") << QByteArray("filename"); + QTest::newRow("NormalStringEncoded") << QByteArray("file%20name") << QByteArray("file name"); + QTest::newRow("JustEncoded") << QByteArray("%20") << QByteArray(" "); + QTest::newRow("HTTPUrl") << QByteArray("http://qt-project.org") << QByteArray("http://qt-project.org"); + QTest::newRow("HTTPUrlEncoded") << QByteArray("http://qt-project%20org") << QByteArray("http://qt-project org"); + QTest::newRow("EmptyString") << QByteArray("") << QByteArray(""); + QTest::newRow("Task27166") << QByteArray("Fran%C3%A7aise") << QByteArray("Française"); +} + +void tst_QByteArray::fromPercentEncoding() +{ + QFETCH(QByteArray, encodedString); + QFETCH(QByteArray, decodedString); + + QCOMPARE(QByteArray::fromPercentEncoding(encodedString), decodedString); +} + +void tst_QByteArray::toPercentEncoding_data() +{ + QTest::addColumn("decodedString"); + QTest::addColumn("encodedString"); + + QTest::newRow("NormalString") << QByteArray("filename") << QByteArray("filename"); + QTest::newRow("NormalStringEncoded") << QByteArray("file name") << QByteArray("file%20name"); + QTest::newRow("JustEncoded") << QByteArray(" ") << QByteArray("%20"); + QTest::newRow("HTTPUrl") << QByteArray("http://qt-project.org") << QByteArray("http%3A//qt-project.org"); + QTest::newRow("HTTPUrlEncoded") << QByteArray("http://qt-project org") << QByteArray("http%3A//qt-project%20org"); + QTest::newRow("EmptyString") << QByteArray("") << QByteArray(""); + QTest::newRow("Task27166") << QByteArray("Française") << QByteArray("Fran%C3%A7aise"); +} + +void tst_QByteArray::toPercentEncoding() +{ + QFETCH(QByteArray, decodedString); + QFETCH(QByteArray, encodedString); + + QCOMPARE(decodedString.toPercentEncoding("/.").constData(), encodedString.constData()); +} + +void tst_QByteArray::toPercentEncoding2_data() +{ + QTest::addColumn("original"); + QTest::addColumn("encoded"); + QTest::addColumn("excludeInEncoding"); + QTest::addColumn("includeInEncoding"); + + QTest::newRow("test_01") << QByteArray("abcdevghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ012345678-._~") + << QByteArray("abcdevghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ012345678-._~") + << QByteArray("") + << QByteArray(""); + QTest::newRow("test_02") << QByteArray("{\t\n\r^\"abc}") + << QByteArray("%7B%09%0A%0D%5E%22abc%7D") + << QByteArray("") + << QByteArray(""); + QTest::newRow("test_03") << QByteArray("://?#[]@!$&'()*+,;=") + << QByteArray("%3A%2F%2F%3F%23%5B%5D%40%21%24%26%27%28%29%2A%2B%2C%3B%3D") + << QByteArray("") + << QByteArray(""); + QTest::newRow("test_04") << QByteArray("://?#[]@!$&'()*+,;=") + << QByteArray("%3A%2F%2F%3F%23%5B%5D%40!$&'()*+,;=") + << QByteArray("!$&'()*+,;=") + << QByteArray(""); + QTest::newRow("test_05") << QByteArray("abcd") + << QByteArray("a%62%63d") + << QByteArray("") + << QByteArray("bc"); +} + +void tst_QByteArray::toPercentEncoding2() +{ + QFETCH(QByteArray, original); + QFETCH(QByteArray, encoded); + QFETCH(QByteArray, excludeInEncoding); + QFETCH(QByteArray, includeInEncoding); + + QByteArray encodedData = original.toPercentEncoding(excludeInEncoding, includeInEncoding); + QCOMPARE(encodedData.constData(), encoded.constData()); + QCOMPARE(original, QByteArray::fromPercentEncoding(encodedData)); +} + +void tst_QByteArray::compare_data() +{ + QTest::addColumn("str1"); + QTest::addColumn("str2"); + QTest::addColumn("result"); + + QTest::newRow("null") << QByteArray() << QByteArray() << 0; + QTest::newRow("null-empty")<< QByteArray() << QByteArray("") << 0; + QTest::newRow("empty-null")<< QByteArray("") << QByteArray() << 0; + QTest::newRow("null-full") << QByteArray() << QByteArray("abc") << -1; + QTest::newRow("full-null") << QByteArray("abc") << QByteArray() << +1; + QTest::newRow("empty-full")<< QByteArray("") << QByteArray("abc") << -1; + QTest::newRow("full-empty")<< QByteArray("abc") << QByteArray("") << +1; + QTest::newRow("rawempty-full") << QByteArray::fromRawData("abc", 0) << QByteArray("abc") << -1; + QTest::newRow("full-rawempty") << QByteArray("abc") << QByteArray::fromRawData("abc", 0) << +1; + + QTest::newRow("equal 1") << QByteArray("abc") << QByteArray("abc") << 0; + QTest::newRow("equal 2") << QByteArray::fromRawData("abc", 3) << QByteArray("abc") << 0; + QTest::newRow("equal 3") << QByteArray::fromRawData("abcdef", 3) << QByteArray("abc") << 0; + QTest::newRow("equal 4") << QByteArray("abc") << QByteArray::fromRawData("abc", 3) << 0; + QTest::newRow("equal 5") << QByteArray("abc") << QByteArray::fromRawData("abcdef", 3) << 0; + QTest::newRow("equal 6") << QByteArray("a\0bc", 4) << QByteArray("a\0bc", 4) << 0; + QTest::newRow("equal 7") << QByteArray::fromRawData("a\0bcdef", 4) << QByteArray("a\0bc", 4) << 0; + QTest::newRow("equal 8") << QByteArray("a\0bc", 4) << QByteArray::fromRawData("a\0bcdef", 4) << 0; + + QTest::newRow("less 1") << QByteArray("000") << QByteArray("abc") << -1; + QTest::newRow("less 2") << QByteArray::fromRawData("00", 3) << QByteArray("abc") << -1; + QTest::newRow("less 3") << QByteArray("000") << QByteArray::fromRawData("abc", 3) << -1; + QTest::newRow("less 4") << QByteArray("abc", 3) << QByteArray("abc", 4) << -1; + QTest::newRow("less 5") << QByteArray::fromRawData("abc\0", 3) << QByteArray("abc\0", 4) << -1; + QTest::newRow("less 6") << QByteArray("a\0bc", 4) << QByteArray("a\0bd", 4) << -1; + + QTest::newRow("greater 1") << QByteArray("abc") << QByteArray("000") << +1; + QTest::newRow("greater 2") << QByteArray("abc") << QByteArray::fromRawData("00", 3) << +1; + QTest::newRow("greater 3") << QByteArray("abcd") << QByteArray::fromRawData("abcd", 3) << +1; + QTest::newRow("greater 4") << QByteArray("a\0bc", 4) << QByteArray("a\0bb", 4) << +1; +} + +void tst_QByteArray::compare() +{ + QFETCH(QByteArray, str1); + QFETCH(QByteArray, str2); + QFETCH(int, result); + + const bool isEqual = result == 0; + const bool isLess = result < 0; + const bool isGreater = result > 0; + + int cmp = str1.compare(str2); + if (cmp) + cmp = (cmp < 0 ? -1 : 1); + + QCOMPARE(cmp, result); + + // basic tests: + QCOMPARE(str1 == str2, isEqual); + QCOMPARE(str1 < str2, isLess); + QCOMPARE(str1 > str2, isGreater); + + // composed tests: + QCOMPARE(str1 <= str2, isLess || isEqual); + QCOMPARE(str1 >= str2, isGreater || isEqual); + QCOMPARE(str1 != str2, !isEqual); + + // inverted tests: + QCOMPARE(str2 == str1, isEqual); + QCOMPARE(str2 < str1, isGreater); + QCOMPARE(str2 > str1, isLess); + + // composed, inverted tests: + QCOMPARE(str2 <= str1, isGreater || isEqual); + QCOMPARE(str2 >= str1, isLess || isEqual); + QCOMPARE(str2 != str1, !isEqual); + + if (isEqual) + QVERIFY(qHash(str1) == qHash(str2)); +} + +void tst_QByteArray::compareCharStar_data() +{ + QTest::addColumn("str1"); + QTest::addColumn("string2"); + QTest::addColumn("result"); + + QTest::newRow("null-null") << QByteArray() << QString() << 0; + QTest::newRow("null-empty") << QByteArray() << "" << 0; + QTest::newRow("null-full") << QByteArray() << "abc" << -1; + QTest::newRow("empty-null") << QByteArray("") << QString() << 0; + QTest::newRow("empty-empty") << QByteArray("") << "" << 0; + QTest::newRow("empty-full") << QByteArray("") << "abc" << -1; + QTest::newRow("raw-null") << QByteArray::fromRawData("abc", 0) << QString() << 0; + QTest::newRow("raw-empty") << QByteArray::fromRawData("abc", 0) << QString("") << 0; + QTest::newRow("raw-full") << QByteArray::fromRawData("abc", 0) << "abc" << -1; + + QTest::newRow("full-null") << QByteArray("abc") << QString() << +1; + QTest::newRow("full-empty") << QByteArray("abc") << "" << +1; + + QTest::newRow("equal1") << QByteArray("abc") << "abc" << 0; + QTest::newRow("equal2") << QByteArray("abcd", 3) << "abc" << 0; + QTest::newRow("equal3") << QByteArray::fromRawData("abcd", 3) << "abc" << 0; + + QTest::newRow("less1") << QByteArray("ab") << "abc" << -1; + QTest::newRow("less2") << QByteArray("abb") << "abc" << -1; + QTest::newRow("less3") << QByteArray::fromRawData("abc", 2) << "abc" << -1; + QTest::newRow("less4") << QByteArray("", 1) << "abc" << -1; + QTest::newRow("less5") << QByteArray::fromRawData("", 1) << "abc" << -1; + QTest::newRow("less6") << QByteArray("a\0bc", 4) << "a.bc" << -1; + + QTest::newRow("greater1") << QByteArray("ac") << "abc" << +1; + QTest::newRow("greater2") << QByteArray("abd") << "abc" << +1; + QTest::newRow("greater3") << QByteArray("abcd") << "abc" << +1; + QTest::newRow("greater4") << QByteArray::fromRawData("abcd", 4) << "abc" << +1; +} + +void tst_QByteArray::compareCharStar() +{ + QFETCH(QByteArray, str1); + QFETCH(QString, string2); + QFETCH(int, result); + + const bool isEqual = result == 0; + const bool isLess = result < 0; + const bool isGreater = result > 0; + QByteArray qba = string2.toLatin1(); + const char *str2 = qba.constData(); + if (string2.isNull()) + str2 = 0; + + // basic tests: + QCOMPARE(str1 == str2, isEqual); + QCOMPARE(str1 < str2, isLess); + QCOMPARE(str1 > str2, isGreater); + + // composed tests: + QCOMPARE(str1 <= str2, isLess || isEqual); + QCOMPARE(str1 >= str2, isGreater || isEqual); + QCOMPARE(str1 != str2, !isEqual); + + // inverted tests: + QCOMPARE(str2 == str1, isEqual); + QCOMPARE(str2 < str1, isGreater); + QCOMPARE(str2 > str1, isLess); + + // composed, inverted tests: + QCOMPARE(str2 <= str1, isGreater || isEqual); + QCOMPARE(str2 >= str1, isLess || isEqual); + QCOMPARE(str2 != str1, !isEqual); +} + +void tst_QByteArray::repeatedSignature() const +{ + /* repated() should be a const member. */ + const QByteArray string; + (void)string.repeated(3); +} + +void tst_QByteArray::repeated() const +{ + QFETCH(QByteArray, string); + QFETCH(QByteArray, expected); + QFETCH(int, count); + + QCOMPARE(string.repeated(count), expected); +} + +void tst_QByteArray::repeated_data() const +{ + QTest::addColumn("string" ); + QTest::addColumn("expected" ); + QTest::addColumn("count" ); + + /* Empty strings. */ + QTest::newRow("data1") + << QByteArray() + << QByteArray() + << 0; + + QTest::newRow("data2") + << QByteArray() + << QByteArray() + << -1004; + + QTest::newRow("data3") + << QByteArray() + << QByteArray() + << 1; + + QTest::newRow("data4") + << QByteArray() + << QByteArray() + << 5; + + /* On simple string. */ + QTest::newRow("data5") + << QByteArray("abc") + << QByteArray() + << -1004; + + QTest::newRow("data6") + << QByteArray("abc") + << QByteArray() + << -1; + + QTest::newRow("data7") + << QByteArray("abc") + << QByteArray() + << 0; + + QTest::newRow("data8") + << QByteArray("abc") + << QByteArray("abc") + << 1; + + QTest::newRow("data9") + << QByteArray(("abc")) + << QByteArray(("abcabc")) + << 2; + + QTest::newRow("data10") + << QByteArray(("abc")) + << QByteArray(("abcabcabc")) + << 3; + + QTest::newRow("data11") + << QByteArray(("abc")) + << QByteArray(("abcabcabcabc")) + << 4; + + QTest::newRow("static not null terminated") + << QByteArray(staticNotNullTerminated) + << QByteArray("datadatadatadata") + << 4; + QTest::newRow("static standard") + << QByteArray(staticStandard) + << QByteArray("datadatadatadata") + << 4; + QTest::newRow("static shifted not null terminated") + << QByteArray(staticShiftedNotNullTerminated) + << QByteArray("datadatadatadata") + << 4; + QTest::newRow("static shifted") + << QByteArray(staticShifted) + << QByteArray("datadatadatadata") + << 4; +} + +void tst_QByteArray::byteRefDetaching() const +{ + { + QByteArray str = "str"; + QByteArray copy; + copy[0] = 'S'; + + QCOMPARE(str, QByteArray("str")); + } + + { + char buf[] = { 's', 't', 'r' }; + QByteArray str = QByteArray::fromRawData(buf, 3); + str[0] = 'S'; + + QCOMPARE(buf[0], char('s')); + } + + { + static const char buf[] = { 's', 't', 'r' }; + QByteArray str = QByteArray::fromRawData(buf, 3); + + // this causes a crash in most systems if the detaching doesn't work + str[0] = 'S'; + + QCOMPARE(buf[0], char('s')); + } +} + +void tst_QByteArray::reserve() +{ + int capacity = 100; + QByteArray qba; + qba.reserve(capacity); + QVERIFY(qba.capacity() == capacity); + char *data = qba.data(); + + for (int i = 0; i < capacity; i++) { + qba.resize(i); + QVERIFY(capacity == qba.capacity()); + QVERIFY(data == qba.data()); + } + + qba.resize(capacity); + + QByteArray copy = qba; + qba.reserve(capacity / 2); + QCOMPARE(qba.size(), capacity); // we didn't shrink the size! + QCOMPARE(qba.capacity(), capacity); + QCOMPARE(copy.capacity(), capacity); + + qba = copy; + qba.reserve(capacity * 2); + QCOMPARE(qba.size(), capacity); + QCOMPARE(qba.capacity(), capacity * 2); + QCOMPARE(copy.capacity(), capacity); + QVERIFY(qba.constData() != data); + + QByteArray nil1, nil2; + nil1.reserve(0); + nil2.squeeze(); + nil1.squeeze(); + nil2.reserve(0); +} + +void tst_QByteArray::reserveExtended_data() +{ + prependExtended_data(); +} + +void tst_QByteArray::reserveExtended() +{ + QFETCH(QByteArray, array); + array.reserve(1024); + QVERIFY(array.capacity() == 1024); + QCOMPARE(array, QByteArray("data")); + array.squeeze(); + QCOMPARE(array, QByteArray("data")); + QCOMPARE(array.capacity(), array.size()); +} + +void tst_QByteArray::movablity_data() +{ + QTest::addColumn("array"); + + QTest::newRow("0x00000000") << QByteArray("\x00\x00\x00\x00", 4); + QTest::newRow("0x000000ff") << QByteArray("\x00\x00\x00\xff", 4); + QTest::newRow("0xffffffff") << QByteArray("\xff\xff\xff\xff", 4); + QTest::newRow("empty") << QByteArray(""); + QTest::newRow("null") << QByteArray(); + QTest::newRow("sss") << QByteArray(3, 's'); + + prependExtended_data(); +} + +void tst_QByteArray::movablity() +{ + QFETCH(QByteArray, array); + + Q_STATIC_ASSERT(!QTypeInfo::isStatic); + + const int size = array.size(); + const bool isEmpty = array.isEmpty(); + const bool isNull = array.isNull(); + const int capacity = array.capacity(); + + QByteArray memSpace; + + // we need only memory space not the instance + memSpace.~QByteArray(); + // move array -> memSpace + memcpy((void *)&memSpace, (const void *)&array, sizeof(QByteArray)); + // reconstruct empty QByteArray + new (&array) QByteArray; + + QCOMPARE(memSpace.size(), size); + QCOMPARE(memSpace.isEmpty(), isEmpty); + QCOMPARE(memSpace.isNull(), isNull); + QCOMPARE(memSpace.capacity(), capacity); + + // try to not crash + (void)memSpace.toLower(); + (void)memSpace.toUpper(); + memSpace.prepend('a'); + memSpace.append("b", 1); + memSpace.squeeze(); + memSpace.reserve(array.size() + 16); + + QByteArray copy(memSpace); + + // reinitialize base values + const int newSize = size + 2; + const bool newIsEmpty = false; + const bool newIsNull = false; + const int newCapacity = 16; + + // move back memSpace -> array + array.~QByteArray(); + memcpy((void *)&array, (const void *)&memSpace, sizeof(QByteArray)); + // reconstruct empty QByteArray + new (&memSpace) QByteArray; + + QCOMPARE(array.size(), newSize); + QCOMPARE(array.isEmpty(), newIsEmpty); + QCOMPARE(array.isNull(), newIsNull); + QCOMPARE(array.capacity(), newCapacity); + QVERIFY(array.startsWith('a')); + QVERIFY(array.endsWith('b')); + + QCOMPARE(copy.size(), newSize); + QCOMPARE(copy.isEmpty(), newIsEmpty); + QCOMPARE(copy.isNull(), newIsNull); + QCOMPARE(copy.capacity(), newCapacity); + QVERIFY(copy.startsWith('a')); + QVERIFY(copy.endsWith('b')); + + // try to not crash + array.squeeze(); + array.reserve(array.size() + 3); + QVERIFY(true); +} + +// Only tested on c++0x compliant compiler or gcc +void tst_QByteArray::literals() +{ + QByteArray str(QByteArrayLiteral("abcd")); + + QVERIFY(str.length() == 4); + QVERIFY(str == "abcd"); + QVERIFY(str.data_ptr()->ref.isStatic()); + QVERIFY(str.data_ptr()->offset == sizeof(QByteArrayData)); + + const char *s = str.constData(); + QByteArray str2 = str; + QVERIFY(str2.constData() == s); + + // detach on non const access + QVERIFY(str.data() != s); + + QVERIFY(str2.constData() == s); + QVERIFY(str2.data() != s); +} + +void tst_QByteArray::toUpperLower_data() +{ + QTest::addColumn("input"); + QTest::addColumn("upper"); + QTest::addColumn("lower"); + + QTest::newRow("empty") << QByteArray() << QByteArray() << QByteArray(); + QTest::newRow("literal") << QByteArrayLiteral("Hello World") + << QByteArrayLiteral("HELLO WORLD") + << QByteArrayLiteral("hello world"); + QTest::newRow("ascii") << QByteArray("Hello World, this is a STRING") + << QByteArray("HELLO WORLD, THIS IS A STRING") + << QByteArray("hello world, this is a string"); + QTest::newRow("latin1") << QByteArray("R\311sum\351") + << QByteArray("R\311SUM\311") + << QByteArray("r\351sum\351"); + QTest::newRow("nul") << QByteArray("a\0B", 3) << QByteArray("A\0B", 3) << QByteArray("a\0b", 3); +} + +void tst_QByteArray::toUpperLower() +{ + QFETCH(QByteArray, input); + QFETCH(QByteArray, upper); + QFETCH(QByteArray, lower); + QCOMPARE(lower.toLower(), lower); + QCOMPARE(upper.toUpper(), upper); + QCOMPARE(input.toUpper(), upper); + QCOMPARE(input.toLower(), lower); + + QByteArray copy = input; + QCOMPARE(std::move(copy).toUpper(), upper); + copy = input; + copy.detach(); + QCOMPARE(std::move(copy).toUpper(), upper); + + copy = input; + QCOMPARE(std::move(copy).toLower(), lower); + copy = input; + copy.detach(); + QCOMPARE(std::move(copy).toLower(), lower); + + copy = lower; + QCOMPARE(std::move(copy).toLower(), lower); + copy = lower; + copy.detach(); + QCOMPARE(std::move(copy).toLower(), lower); + + copy = upper; + QCOMPARE(std::move(copy).toUpper(), upper); + copy = upper; + copy.detach(); + QCOMPARE(std::move(copy).toUpper(), upper); +} + +void tst_QByteArray::isUpper() +{ + QVERIFY(!QByteArray().isUpper()); + QVERIFY(!QByteArray("").isUpper()); + QVERIFY(QByteArray("TEXT").isUpper()); + QVERIFY(QByteArray("\xD0\xDE").isUpper()); + QVERIFY(!QByteArray("\xD7").isUpper()); // multiplication sign is not upper + QVERIFY(!QByteArray("\xDF").isUpper()); // sz ligature is not upper + QVERIFY(!QByteArray("text").isUpper()); + QVERIFY(!QByteArray("Text").isUpper()); + QVERIFY(!QByteArray("tExt").isUpper()); + QVERIFY(!QByteArray("teXt").isUpper()); + QVERIFY(!QByteArray("texT").isUpper()); + QVERIFY(!QByteArray("TExt").isUpper()); + QVERIFY(!QByteArray("teXT").isUpper()); + QVERIFY(!QByteArray("tEXt").isUpper()); + QVERIFY(!QByteArray("tExT").isUpper()); + QVERIFY(!QByteArray("@ABYZ[").isUpper()); + QVERIFY(!QByteArray("@abyz[").isUpper()); + QVERIFY(!QByteArray("`ABYZ{").isUpper()); + QVERIFY(!QByteArray("`abyz{").isUpper()); +} + +void tst_QByteArray::isLower() +{ + QVERIFY(!QByteArray().isLower()); + QVERIFY(!QByteArray("").isLower()); + QVERIFY(QByteArray("text").isLower()); + QVERIFY(QByteArray("\xE0\xFF").isLower()); + QVERIFY(!QByteArray("\xF7").isLower()); // division sign is not lower + QVERIFY(!QByteArray("Text").isLower()); + QVERIFY(!QByteArray("tExt").isLower()); + QVERIFY(!QByteArray("teXt").isLower()); + QVERIFY(!QByteArray("texT").isLower()); + QVERIFY(!QByteArray("TExt").isLower()); + QVERIFY(!QByteArray("teXT").isLower()); + QVERIFY(!QByteArray("tEXt").isLower()); + QVERIFY(!QByteArray("tExT").isLower()); + QVERIFY(!QByteArray("TEXT").isLower()); + QVERIFY(!QByteArray("@ABYZ[").isLower()); + QVERIFY(!QByteArray("@abyz[").isLower()); + QVERIFY(!QByteArray("`ABYZ{").isLower()); + QVERIFY(!QByteArray("`abyz{").isLower()); +} + +void tst_QByteArray::macTypes() +{ +#ifndef Q_OS_MAC + QSKIP("This is a Apple-only test"); +#else + extern void tst_QByteArray_macTypes(); // in qbytearray_mac.mm + tst_QByteArray_macTypes(); +#endif +} + +void tst_QByteArray::stdString() +{ + std::string stdstr( "QByteArray" ); + + const QByteArray stlqt = QByteArray::fromStdString(stdstr); + QCOMPARE(stlqt.length(), int(stdstr.length())); + QCOMPARE(stlqt.data(), stdstr.c_str()); + QCOMPARE(stlqt.toStdString(), stdstr); + + std::string utf8str( "Nøt æscii" ); + const QByteArray u8 = QByteArray::fromStdString(utf8str); + const QByteArray l1 = QString::fromUtf8(u8).toLatin1(); + std::string l1str = l1.toStdString(); + QVERIFY(l1str.length() < utf8str.length()); +} + + +const char globalChar = '1'; + +QTEST_MAIN(tst_QByteArray) +#include "tst_qbytearray.moc" diff --git a/tests/auto/corelib/text/qbytearray/tst_qbytearray_mac.mm b/tests/auto/corelib/text/qbytearray/tst_qbytearray_mac.mm new file mode 100644 index 0000000000..98146e3525 --- /dev/null +++ b/tests/auto/corelib/text/qbytearray/tst_qbytearray_mac.mm @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Samuel Gaist +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +#include +#include + +void tst_QByteArray_macTypes() +{ + // QByteArray <-> CFData + { + QByteArray qtByteArray("test bytearray"); + const CFDataRef cfData = qtByteArray.toCFData(); + QCOMPARE(QByteArray::fromCFData(cfData), qtByteArray); + CFRelease(cfData); + } + { + QByteArray qtByteArray("test bytearray"); + const CFDataRef cfData = qtByteArray.toCFData(); + QByteArray qtByteArrayCopy(qtByteArray); + qtByteArray = qtByteArray.toUpper(); // modify + QCOMPARE(QByteArray::fromCFData(cfData), qtByteArrayCopy); + } + // QByteArray <-> CFData Raw + { + QByteArray qtByteArray("test bytearray"); + const CFDataRef cfData = qtByteArray.toRawCFData(); + const UInt8 * cfDataPtr = CFDataGetBytePtr(cfData); + QCOMPARE(reinterpret_cast(qtByteArray.constData()), cfDataPtr); + CFRelease(cfData); + } + { + const UInt8 data[] = "cfdata test"; + const CFDataRef cfData = CFDataCreate(kCFAllocatorDefault, data, sizeof(data)); + const UInt8 * cfDataPtr = CFDataGetBytePtr(cfData); + QByteArray qtByteArray = QByteArray::fromRawCFData(cfData); + QCOMPARE(reinterpret_cast(qtByteArray.constData()), cfDataPtr); + CFRelease(cfData); + } + // QByteArray <-> NSData + { + QMacAutoReleasePool pool; + QByteArray qtByteArray("test bytearray"); + const NSData *nsData = qtByteArray.toNSData(); + QCOMPARE(QByteArray::fromNSData(nsData), qtByteArray); + } + { + QMacAutoReleasePool pool; + QByteArray qtByteArray("test bytearray"); + const NSData *nsData = qtByteArray.toNSData(); + QByteArray qtByteArrayCopy(qtByteArray); + qtByteArray = qtByteArray.toUpper(); // modify + QCOMPARE(QByteArray::fromNSData(nsData), qtByteArrayCopy); + } + // QByteArray <-> NSData Raw + { + QMacAutoReleasePool pool; + QByteArray qtByteArray("test bytearray"); + const NSData *nsData = qtByteArray.toRawNSData(); + QCOMPARE([nsData bytes], qtByteArray.constData()); + } + { + QMacAutoReleasePool pool; + const char data[] = "nsdata test"; + const NSData *nsData = [NSData dataWithBytes:data length:sizeof(data)]; + QByteArray qtByteArray = QByteArray::fromRawNSData(nsData); + QCOMPARE(qtByteArray.constData(), [nsData bytes]); + } +} -- cgit v1.2.3