| @@ -482,17 +482,16 @@ public: | |||
| template <class F1, class E1, class F2, class E2> | |||
| struct Test5 | |||
| { | |||
| static void test (UnitTest& unitTest) | |||
| static void test (UnitTest& unitTest, Random& r) | |||
| { | |||
| test (unitTest, false); | |||
| test (unitTest, true); | |||
| test (unitTest, false, r); | |||
| test (unitTest, true, r); | |||
| } | |||
| static void test (UnitTest& unitTest, bool inPlace) | |||
| static void test (UnitTest& unitTest, bool inPlace, Random& r) | |||
| { | |||
| const int numSamples = 2048; | |||
| int32 original [numSamples], converted [numSamples], reversed [numSamples]; | |||
| Random r; | |||
| { | |||
| AudioData::Pointer<F1, E1, AudioData::NonInterleaved, AudioData::NonConst> d (original); | |||
| @@ -549,49 +548,50 @@ public: | |||
| template <class F1, class E1, class FormatType> | |||
| struct Test3 | |||
| { | |||
| static void test (UnitTest& unitTest) | |||
| static void test (UnitTest& unitTest, Random& r) | |||
| { | |||
| Test5 <F1, E1, FormatType, AudioData::BigEndian>::test (unitTest); | |||
| Test5 <F1, E1, FormatType, AudioData::LittleEndian>::test (unitTest); | |||
| Test5 <F1, E1, FormatType, AudioData::BigEndian>::test (unitTest, r); | |||
| Test5 <F1, E1, FormatType, AudioData::LittleEndian>::test (unitTest, r); | |||
| } | |||
| }; | |||
| template <class FormatType, class Endianness> | |||
| struct Test2 | |||
| { | |||
| static void test (UnitTest& unitTest) | |||
| static void test (UnitTest& unitTest, Random& r) | |||
| { | |||
| Test3 <FormatType, Endianness, AudioData::Int8>::test (unitTest); | |||
| Test3 <FormatType, Endianness, AudioData::UInt8>::test (unitTest); | |||
| Test3 <FormatType, Endianness, AudioData::Int16>::test (unitTest); | |||
| Test3 <FormatType, Endianness, AudioData::Int24>::test (unitTest); | |||
| Test3 <FormatType, Endianness, AudioData::Int32>::test (unitTest); | |||
| Test3 <FormatType, Endianness, AudioData::Float32>::test (unitTest); | |||
| Test3 <FormatType, Endianness, AudioData::Int8>::test (unitTest, r); | |||
| Test3 <FormatType, Endianness, AudioData::UInt8>::test (unitTest, r); | |||
| Test3 <FormatType, Endianness, AudioData::Int16>::test (unitTest, r); | |||
| Test3 <FormatType, Endianness, AudioData::Int24>::test (unitTest, r); | |||
| Test3 <FormatType, Endianness, AudioData::Int32>::test (unitTest, r); | |||
| Test3 <FormatType, Endianness, AudioData::Float32>::test (unitTest, r); | |||
| } | |||
| }; | |||
| template <class FormatType> | |||
| struct Test1 | |||
| { | |||
| static void test (UnitTest& unitTest) | |||
| static void test (UnitTest& unitTest, Random& r) | |||
| { | |||
| Test2 <FormatType, AudioData::BigEndian>::test (unitTest); | |||
| Test2 <FormatType, AudioData::LittleEndian>::test (unitTest); | |||
| Test2 <FormatType, AudioData::BigEndian>::test (unitTest, r); | |||
| Test2 <FormatType, AudioData::LittleEndian>::test (unitTest, r); | |||
| } | |||
| }; | |||
| void runTest() | |||
| { | |||
| Random r = getRandom(); | |||
| beginTest ("Round-trip conversion: Int8"); | |||
| Test1 <AudioData::Int8>::test (*this); | |||
| Test1 <AudioData::Int8>::test (*this, r); | |||
| beginTest ("Round-trip conversion: Int16"); | |||
| Test1 <AudioData::Int16>::test (*this); | |||
| Test1 <AudioData::Int16>::test (*this, r); | |||
| beginTest ("Round-trip conversion: Int24"); | |||
| Test1 <AudioData::Int24>::test (*this); | |||
| Test1 <AudioData::Int24>::test (*this, r); | |||
| beginTest ("Round-trip conversion: Int32"); | |||
| Test1 <AudioData::Int32>::test (*this); | |||
| Test1 <AudioData::Int32>::test (*this, r); | |||
| beginTest ("Round-trip conversion: Float32"); | |||
| Test1 <AudioData::Float32>::test (*this); | |||
| Test1 <AudioData::Float32>::test (*this, r); | |||
| } | |||
| }; | |||
| @@ -141,8 +141,8 @@ public: | |||
| class WriteThread : public Thread | |||
| { | |||
| public: | |||
| WriteThread (AbstractFifo& fifo_, int* buffer_) | |||
| : Thread ("fifo writer"), fifo (fifo_), buffer (buffer_) | |||
| WriteThread (AbstractFifo& f, int* b, Random rng) | |||
| : Thread ("fifo writer"), fifo (f), buffer (b), random (rng) | |||
| { | |||
| startThread(); | |||
| } | |||
| @@ -155,11 +155,10 @@ public: | |||
| void run() | |||
| { | |||
| int n = 0; | |||
| Random r; | |||
| while (! threadShouldExit()) | |||
| { | |||
| int num = r.nextInt (2000) + 1; | |||
| int num = random.nextInt (2000) + 1; | |||
| int start1, size1, start2, size2; | |||
| fifo.prepareToWrite (num, start1, size1, start2, size2); | |||
| @@ -181,6 +180,7 @@ public: | |||
| private: | |||
| AbstractFifo& fifo; | |||
| int* buffer; | |||
| Random random; | |||
| }; | |||
| void runTest() | |||
| @@ -190,10 +190,11 @@ public: | |||
| int buffer [5000]; | |||
| AbstractFifo fifo (numElementsInArray (buffer)); | |||
| WriteThread writer (fifo, buffer); | |||
| WriteThread writer (fifo, buffer, getRandom()); | |||
| int n = 0; | |||
| Random r; | |||
| Random r = getRandom(); | |||
| r.combineSeed (12345); | |||
| for (int count = 100000; --count >= 0;) | |||
| { | |||
| @@ -616,8 +616,7 @@ public: | |||
| void runTest() | |||
| { | |||
| beginTest ("JSON"); | |||
| Random r; | |||
| r.setSeedRandomly(); | |||
| Random r = getRandom(); | |||
| expect (JSON::parse (String::empty) == var::null); | |||
| expect (JSON::parse ("{}").isObject()); | |||
| @@ -953,10 +953,10 @@ String BigInteger::toString (const int base, const int minimumNumCharacters) con | |||
| return isNegative() ? "-" + s : s; | |||
| } | |||
| void BigInteger::parseString (const String& text, const int base) | |||
| void BigInteger::parseString (StringRef text, const int base) | |||
| { | |||
| clear(); | |||
| String::CharPointerType t (text.getCharPointer().findEndOfWhitespace()); | |||
| String::CharPointerType t (text.text.findEndOfWhitespace()); | |||
| setNegative (*t == (juce_wchar) '-'); | |||
| @@ -282,7 +282,7 @@ public: | |||
| Specify a base such as 2 (binary), 8 (octal), 10 (decimal), 16 (hex). | |||
| Any invalid characters will be ignored. | |||
| */ | |||
| void parseString (const String& text, int base); | |||
| void parseString (StringRef text, int base); | |||
| //============================================================================== | |||
| /** Turns the number into a block of binary data. | |||
| @@ -26,13 +26,11 @@ | |||
| ============================================================================== | |||
| */ | |||
| Random::Random (const int64 seedValue) noexcept | |||
| : seed (seedValue) | |||
| Random::Random (const int64 seedValue) noexcept : seed (seedValue) | |||
| { | |||
| } | |||
| Random::Random() | |||
| : seed (1) | |||
| Random::Random() : seed (1) | |||
| { | |||
| setSeedRandomly(); | |||
| } | |||
| @@ -163,24 +161,20 @@ public: | |||
| { | |||
| beginTest ("Random"); | |||
| for (int j = 10; --j >= 0;) | |||
| Random r = getRandom(); | |||
| for (int i = 2000; --i >= 0;) | |||
| { | |||
| Random r; | |||
| r.setSeedRandomly(); | |||
| for (int i = 20; --i >= 0;) | |||
| { | |||
| expect (r.nextDouble() >= 0.0 && r.nextDouble() < 1.0); | |||
| expect (r.nextFloat() >= 0.0f && r.nextFloat() < 1.0f); | |||
| expect (r.nextInt (5) >= 0 && r.nextInt (5) < 5); | |||
| expect (r.nextInt (1) == 0); | |||
| int n = r.nextInt (50) + 1; | |||
| expect (r.nextInt (n) >= 0 && r.nextInt (n) < n); | |||
| n = r.nextInt (0x7ffffffe) + 1; | |||
| expect (r.nextInt (n) >= 0 && r.nextInt (n) < n); | |||
| } | |||
| expect (r.nextDouble() >= 0.0 && r.nextDouble() < 1.0); | |||
| expect (r.nextFloat() >= 0.0f && r.nextFloat() < 1.0f); | |||
| expect (r.nextInt (5) >= 0 && r.nextInt (5) < 5); | |||
| expect (r.nextInt (1) == 0); | |||
| int n = r.nextInt (50) + 1; | |||
| expect (r.nextInt (n) >= 0 && r.nextInt (n) < n); | |||
| n = r.nextInt (0x7ffffffe) + 1; | |||
| expect (r.nextInt (n) >= 0 && r.nextInt (n) < n); | |||
| } | |||
| } | |||
| }; | |||
| @@ -59,7 +59,6 @@ public: | |||
| ~Random() noexcept; | |||
| /** Returns the next random 32 bit integer. | |||
| @returns a random integer from the full range 0x80000000 to 0x7fffffff | |||
| */ | |||
| int nextInt() noexcept; | |||
| @@ -71,29 +70,24 @@ public: | |||
| int nextInt (int maxValue) noexcept; | |||
| /** Returns the next 64-bit random number. | |||
| @returns a random integer from the full range 0x8000000000000000 to 0x7fffffffffffffff | |||
| */ | |||
| int64 nextInt64() noexcept; | |||
| /** Returns the next random floating-point number. | |||
| @returns a random value in the range 0 to 1.0 | |||
| */ | |||
| float nextFloat() noexcept; | |||
| /** Returns the next random floating-point number. | |||
| @returns a random value in the range 0 to 1.0 | |||
| */ | |||
| double nextDouble() noexcept; | |||
| /** Returns the next random boolean value. | |||
| */ | |||
| /** Returns the next random boolean value. */ | |||
| bool nextBool() noexcept; | |||
| /** Returns a BigInteger containing a random number. | |||
| @returns a random value in the range 0 to (maximumValue - 1). | |||
| */ | |||
| BigInteger nextLargeNumber (const BigInteger& maximumValue); | |||
| @@ -108,6 +102,9 @@ public: | |||
| /** Resets this Random object to a given seed value. */ | |||
| void setSeed (int64 newSeed) noexcept; | |||
| /** Returns the RNG's current seed. */ | |||
| int64 getSeed() const noexcept { return seed; } | |||
| /** Merges this object's seed with another value. | |||
| This sets the seed to be a value created by combining the current seed and this | |||
| new value. | |||
| @@ -317,11 +317,11 @@ void MemoryBlock::setBitRange (const size_t bitRangeStart, size_t numBits, int b | |||
| } | |||
| //============================================================================== | |||
| void MemoryBlock::loadFromHexString (const String& hex) | |||
| void MemoryBlock::loadFromHexString (StringRef hex) | |||
| { | |||
| ensureSize ((size_t) hex.length() >> 1); | |||
| char* dest = data; | |||
| String::CharPointerType t (hex.getCharPointer()); | |||
| String::CharPointerType t (hex.text); | |||
| for (;;) | |||
| { | |||
| @@ -373,27 +373,27 @@ String MemoryBlock::toBase64Encoding() const | |||
| return destString; | |||
| } | |||
| bool MemoryBlock::fromBase64Encoding (const String& s) | |||
| bool MemoryBlock::fromBase64Encoding (StringRef s) | |||
| { | |||
| const int startPos = s.indexOfChar ('.') + 1; | |||
| String::CharPointerType dot (CharacterFunctions::find (s.text, CharPointer_ASCII ("."))); | |||
| if (startPos <= 0) | |||
| if (dot.isEmpty()) | |||
| return false; | |||
| const int numBytesNeeded = s.substring (0, startPos - 1).getIntValue(); | |||
| const int numBytesNeeded = String (s.text, dot).getIntValue(); | |||
| setSize ((size_t) numBytesNeeded, true); | |||
| const int numChars = s.length() - startPos; | |||
| String::CharPointerType srcChars (s.getCharPointer()); | |||
| srcChars += startPos; | |||
| String::CharPointerType srcChars (dot + 1); | |||
| int pos = 0; | |||
| for (int i = 0; i < numChars; ++i) | |||
| for (;;) | |||
| { | |||
| const char c = (char) srcChars.getAndAdvance(); | |||
| if (c == 0) | |||
| return true; | |||
| for (int j = 0; j < 64; ++j) | |||
| { | |||
| if (base64EncodingTable[j] == c) | |||
| @@ -404,6 +404,4 @@ bool MemoryBlock::fromBase64Encoding (const String& s) | |||
| } | |||
| } | |||
| } | |||
| return true; | |||
| } | |||
| @@ -206,7 +206,7 @@ public: | |||
| @see String::toHexString() | |||
| */ | |||
| void loadFromHexString (const String& sourceHexString); | |||
| void loadFromHexString (StringRef sourceHexString); | |||
| //============================================================================== | |||
| /** Sets a number of bits in the memory block, treating it as a long binary sequence. */ | |||
| @@ -235,7 +235,7 @@ public: | |||
| @see toBase64Encoding | |||
| */ | |||
| bool fromBase64Encoding (const String& encodedString); | |||
| bool fromBase64Encoding (StringRef encodedString); | |||
| private: | |||
| @@ -104,12 +104,12 @@ public: | |||
| void runTest() | |||
| { | |||
| beginTest ("Basics"); | |||
| Random r; | |||
| Random r = getRandom(); | |||
| int randomInt = r.nextInt(); | |||
| int64 randomInt64 = r.nextInt64(); | |||
| double randomDouble = r.nextDouble(); | |||
| String randomString (createRandomWideCharString()); | |||
| String randomString (createRandomWideCharString (r)); | |||
| MemoryOutputStream mo; | |||
| mo.writeInt (randomInt); | |||
| @@ -132,10 +132,9 @@ public: | |||
| expect (mi.readDoubleBigEndian() == randomDouble); | |||
| } | |||
| static String createRandomWideCharString() | |||
| static String createRandomWideCharString (Random& r) | |||
| { | |||
| juce_wchar buffer [50] = { 0 }; | |||
| Random r; | |||
| for (int i = 0; i < numElementsInArray (buffer) - 1; ++i) | |||
| { | |||
| @@ -2075,6 +2075,10 @@ String String::fromUTF8 (const char* const buffer, int bufferSizeBytes) | |||
| #endif | |||
| //============================================================================== | |||
| StringRef::StringRef() noexcept : text ("\0\0\0") | |||
| { | |||
| } | |||
| StringRef::StringRef (const String::CharPointerType::CharType* stringLiteral) noexcept : text (stringLiteral) | |||
| { | |||
| jassert (stringLiteral != nullptr); // This must be a valid string literal, not a null pointer!! | |||
| @@ -2086,8 +2090,8 @@ StringRef::StringRef (const String::CharPointerType::CharType* stringLiteral) no | |||
| create them. The source data could be UTF-8, ASCII or one of many local code-pages. | |||
| To get around this problem, you must be more explicit when you pass an ambiguous 8-bit | |||
| string to the String class - so for example if your source data is actually UTF-8, | |||
| you'd call String (CharPointer_UTF8 ("my utf8 string..")), and it would be able to | |||
| string to the StringRef class - so for example if your source data is actually UTF-8, | |||
| you'd call StringRef (CharPointer_UTF8 ("my utf8 string..")), and it would be able to | |||
| correctly convert the multi-byte characters to unicode. It's *highly* recommended that | |||
| you use UTF-8 with escape characters in your source code to represent extended characters, | |||
| because there's no other way to represent these strings in a way that isn't dependent on | |||
| @@ -2116,9 +2120,9 @@ public: | |||
| template <class CharPointerType> | |||
| struct TestUTFConversion | |||
| { | |||
| static void test (UnitTest& test) | |||
| static void test (UnitTest& test, Random& r) | |||
| { | |||
| String s (createRandomWideCharString()); | |||
| String s (createRandomWideCharString (r)); | |||
| typename CharPointerType::CharType buffer [300]; | |||
| @@ -2138,10 +2142,9 @@ public: | |||
| } | |||
| }; | |||
| static String createRandomWideCharString() | |||
| static String createRandomWideCharString (Random& r) | |||
| { | |||
| juce_wchar buffer[50] = { 0 }; | |||
| Random r; | |||
| for (int i = 0; i < numElementsInArray (buffer) - 1; ++i) | |||
| { | |||
| @@ -2162,6 +2165,8 @@ public: | |||
| void runTest() | |||
| { | |||
| Random r = getRandom(); | |||
| { | |||
| beginTest ("Basics"); | |||
| @@ -2402,9 +2407,9 @@ public: | |||
| { | |||
| beginTest ("UTF conversions"); | |||
| TestUTFConversion <CharPointer_UTF32>::test (*this); | |||
| TestUTFConversion <CharPointer_UTF8>::test (*this); | |||
| TestUTFConversion <CharPointer_UTF16>::test (*this); | |||
| TestUTFConversion <CharPointer_UTF32>::test (*this, r); | |||
| TestUTFConversion <CharPointer_UTF8>::test (*this, r); | |||
| TestUTFConversion <CharPointer_UTF16>::test (*this, r); | |||
| } | |||
| { | |||
| @@ -86,6 +86,9 @@ public: | |||
| */ | |||
| StringRef (const String& string) noexcept; | |||
| /** Creates a StringRef pointer to an empty string. */ | |||
| StringRef() noexcept; | |||
| //============================================================================== | |||
| /** Returns a raw pointer to the underlying string data. */ | |||
| operator const String::CharPointerType::CharType*() const noexcept { return text.getAddress(); } | |||
| @@ -191,10 +191,9 @@ class DiffTests : public UnitTest | |||
| public: | |||
| DiffTests() : UnitTest ("TextDiff class") {} | |||
| static String createString() | |||
| static String createString (Random& r) | |||
| { | |||
| juce_wchar buffer[50] = { 0 }; | |||
| Random r; | |||
| for (int i = r.nextInt (49); --i >= 0;) | |||
| { | |||
| @@ -224,6 +223,8 @@ public: | |||
| { | |||
| beginTest ("TextDiff"); | |||
| Random r = getRandom(); | |||
| testDiff (String::empty, String::empty); | |||
| testDiff ("x", String::empty); | |||
| testDiff (String::empty, "x"); | |||
| @@ -234,9 +235,9 @@ public: | |||
| for (int i = 5000; --i >= 0;) | |||
| { | |||
| String s (createString()); | |||
| testDiff (s, createString()); | |||
| testDiff (s + createString(), s + createString()); | |||
| String s (createString (r)); | |||
| testDiff (s, createString (r)); | |||
| testDiff (s + createString (r), s + createString (r)); | |||
| } | |||
| } | |||
| }; | |||
| @@ -26,8 +26,8 @@ | |||
| ============================================================================== | |||
| */ | |||
| UnitTest::UnitTest (const String& name_) | |||
| : name (name_), runner (nullptr) | |||
| UnitTest::UnitTest (const String& nm) | |||
| : name (nm), runner (nullptr) | |||
| { | |||
| getAllTests().add (this); | |||
| } | |||
| @@ -46,10 +46,10 @@ Array<UnitTest*>& UnitTest::getAllTests() | |||
| void UnitTest::initialise() {} | |||
| void UnitTest::shutdown() {} | |||
| void UnitTest::performTest (UnitTestRunner* const runner_) | |||
| void UnitTest::performTest (UnitTestRunner* const newRunner) | |||
| { | |||
| jassert (runner_ != nullptr); | |||
| runner = runner_; | |||
| jassert (newRunner != nullptr); | |||
| runner = newRunner; | |||
| initialise(); | |||
| runTest(); | |||
| @@ -58,22 +58,39 @@ void UnitTest::performTest (UnitTestRunner* const runner_) | |||
| void UnitTest::logMessage (const String& message) | |||
| { | |||
| // This method's only valid while the test is being run! | |||
| jassert (runner != nullptr); | |||
| runner->logMessage (message); | |||
| } | |||
| void UnitTest::beginTest (const String& testName) | |||
| { | |||
| // This method's only valid while the test is being run! | |||
| jassert (runner != nullptr); | |||
| runner->beginNewTest (this, testName); | |||
| } | |||
| void UnitTest::expect (const bool result, const String& failureMessage) | |||
| { | |||
| // This method's only valid while the test is being run! | |||
| jassert (runner != nullptr); | |||
| if (result) | |||
| runner->addPass(); | |||
| else | |||
| runner->addFail (failureMessage); | |||
| } | |||
| Random UnitTest::getRandom() const | |||
| { | |||
| // This method's only valid while the test is being run! | |||
| jassert (runner != nullptr); | |||
| return runner->randomForTest; | |||
| } | |||
| //============================================================================== | |||
| UnitTestRunner::UnitTestRunner() | |||
| : currentTest (nullptr), | |||
| @@ -110,11 +127,17 @@ void UnitTestRunner::resultsUpdated() | |||
| { | |||
| } | |||
| void UnitTestRunner::runTests (const Array<UnitTest*>& tests) | |||
| void UnitTestRunner::runTests (const Array<UnitTest*>& tests, int64 randomSeed) | |||
| { | |||
| results.clear(); | |||
| resultsUpdated(); | |||
| if (randomSeed == 0) | |||
| randomSeed = Random().nextInt (0x7ffffff); | |||
| randomForTest = Random (randomSeed); | |||
| logMessage ("Random seed: 0x" + String::toHexString (randomSeed)); | |||
| for (int i = 0; i < tests.size(); ++i) | |||
| { | |||
| if (shouldAbortTests()) | |||
| @@ -133,9 +156,9 @@ void UnitTestRunner::runTests (const Array<UnitTest*>& tests) | |||
| endTest(); | |||
| } | |||
| void UnitTestRunner::runAllTests() | |||
| void UnitTestRunner::runAllTests (int64 randomSeed) | |||
| { | |||
| runTests (UnitTest::getAllTests()); | |||
| runTests (UnitTest::getAllTests(), randomSeed); | |||
| } | |||
| void UnitTestRunner::logMessage (const String& message) | |||
| @@ -163,6 +163,22 @@ public: | |||
| */ | |||
| void logMessage (const String& message); | |||
| /** Returns a shared RNG that all unit tests should use. | |||
| If a test needs random numbers, it's important that when an error is found, the | |||
| exact circumstances can be re-created in order to re-test the problem, by | |||
| repeating the test with the same random seed value. | |||
| To make this possible, the UnitTestRunner class creates a master seed value | |||
| for the run, writes this number to the log, and then this method returns a | |||
| Random object based on that seed. All tests should only use this method to | |||
| create any Random objects that they need. | |||
| Note that this method will return an identical object each time it's called | |||
| for a given run, so if you need several different Random objects, the best | |||
| way to do that is to call Random::combineSeed() on the result to permute it | |||
| with a constant value. | |||
| */ | |||
| Random getRandom() const; | |||
| private: | |||
| //============================================================================== | |||
| const String name; | |||
| @@ -198,13 +214,19 @@ public: | |||
| The tests are performed in order, and the results are logged. To run all the | |||
| registered UnitTest objects that exist, use runAllTests(). | |||
| If you want to run the tests with a predetermined seed, you can pass that into | |||
| the randomSeed argument, or pass 0 to have a randomly-generated seed chosen. | |||
| */ | |||
| void runTests (const Array<UnitTest*>& tests); | |||
| void runTests (const Array<UnitTest*>& tests, int64 randomSeed = 0); | |||
| /** Runs all the UnitTest objects that currently exist. | |||
| This calls runTests() for all the objects listed in UnitTest::getAllTests(). | |||
| If you want to run the tests with a predetermined seed, you can pass that into | |||
| the randomSeed argument, or pass 0 to have a randomly-generated seed chosen. | |||
| */ | |||
| void runAllTests(); | |||
| void runAllTests (int64 randomSeed = 0); | |||
| /** Sets a flag to indicate whether an assertion should be triggered if a test fails. | |||
| This is true by default. | |||
| @@ -274,6 +296,7 @@ private: | |||
| String currentSubCategory; | |||
| OwnedArray <TestResult, CriticalSection> results; | |||
| bool assertOnFailure, logPasses; | |||
| Random randomForTest; | |||
| void beginNewTest (UnitTest* test, const String& subCategory); | |||
| void endTest(); | |||
| @@ -169,7 +169,7 @@ public: | |||
| void runTest() | |||
| { | |||
| beginTest ("GZIP"); | |||
| Random rng; | |||
| Random rng = getRandom(); | |||
| for (int i = 100; --i >= 0;) | |||
| { | |||
| @@ -221,10 +221,10 @@ MD5::MD5 (CharPointer_UTF8 utf8) noexcept | |||
| processData (utf8.getAddress(), utf8.sizeInBytes() - 1); | |||
| } | |||
| MD5 MD5::fromUTF32 (const String& text) | |||
| MD5 MD5::fromUTF32 (StringRef text) | |||
| { | |||
| MD5Generator generator; | |||
| String::CharPointerType t (text.getCharPointer()); | |||
| String::CharPointerType t (text.text); | |||
| while (! t.isEmpty()) | |||
| { | |||
| @@ -94,7 +94,7 @@ public: | |||
| this operation on it. In new code, you shouldn't use this, and are recommended to | |||
| use the constructor that takes a CharPointer_UTF8 instead. | |||
| */ | |||
| static MD5 fromUTF32 (const String&); | |||
| static MD5 fromUTF32 (StringRef); | |||
| //============================================================================== | |||
| bool operator== (const MD5&) const noexcept; | |||
| @@ -1019,11 +1019,10 @@ class ValueTreeTests : public UnitTest | |||
| public: | |||
| ValueTreeTests() : UnitTest ("ValueTrees") {} | |||
| static String createRandomIdentifier() | |||
| static String createRandomIdentifier (Random& r) | |||
| { | |||
| char buffer[50] = { 0 }; | |||
| const char chars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-:"; | |||
| Random r; | |||
| for (int i = 1 + r.nextInt (numElementsInArray (buffer) - 2); --i >= 0;) | |||
| buffer[i] = chars [r.nextInt (sizeof (chars) - 1)]; | |||
| @@ -1031,10 +1030,9 @@ public: | |||
| return CharPointer_ASCII (buffer); | |||
| } | |||
| static String createRandomWideCharString() | |||
| static String createRandomWideCharString (Random& r) | |||
| { | |||
| juce_wchar buffer[50] = { 0 }; | |||
| Random r; | |||
| for (int i = r.nextInt (numElementsInArray (buffer) - 1); --i >= 0;) | |||
| { | |||
| @@ -1053,20 +1051,19 @@ public: | |||
| return CharPointer_UTF32 (buffer); | |||
| } | |||
| static ValueTree createRandomTree (UndoManager* undoManager, int depth) | |||
| static ValueTree createRandomTree (UndoManager* undoManager, int depth, Random& r) | |||
| { | |||
| Random r; | |||
| ValueTree v (createRandomIdentifier()); | |||
| ValueTree v (createRandomIdentifier (r)); | |||
| for (int i = r.nextInt (10); --i >= 0;) | |||
| { | |||
| switch (r.nextInt (5)) | |||
| { | |||
| case 0: v.setProperty (createRandomIdentifier(), createRandomWideCharString(), undoManager); break; | |||
| case 1: v.setProperty (createRandomIdentifier(), r.nextInt(), undoManager); break; | |||
| case 2: if (depth < 5) v.addChild (createRandomTree (undoManager, depth + 1), r.nextInt (v.getNumChildren() + 1), undoManager); break; | |||
| case 3: v.setProperty (createRandomIdentifier(), r.nextBool(), undoManager); break; | |||
| case 4: v.setProperty (createRandomIdentifier(), r.nextDouble(), undoManager); break; | |||
| case 0: v.setProperty (createRandomIdentifier (r), createRandomWideCharString (r), undoManager); break; | |||
| case 1: v.setProperty (createRandomIdentifier (r), r.nextInt(), undoManager); break; | |||
| case 2: if (depth < 5) v.addChild (createRandomTree (undoManager, depth + 1, r), r.nextInt (v.getNumChildren() + 1), undoManager); break; | |||
| case 3: v.setProperty (createRandomIdentifier (r), r.nextBool(), undoManager); break; | |||
| case 4: v.setProperty (createRandomIdentifier (r), r.nextDouble(), undoManager); break; | |||
| default: break; | |||
| } | |||
| } | |||
| @@ -1077,11 +1074,12 @@ public: | |||
| void runTest() | |||
| { | |||
| beginTest ("ValueTree"); | |||
| Random r = getRandom(); | |||
| for (int i = 10; --i >= 0;) | |||
| { | |||
| MemoryOutputStream mo; | |||
| ValueTree v1 (createRandomTree (nullptr, 0)); | |||
| ValueTree v1 (createRandomTree (nullptr, 0, r)); | |||
| v1.writeToStream (mo); | |||
| MemoryInputStream mi (mo.getData(), mo.getDataSize(), false); | |||
| @@ -1475,12 +1475,12 @@ String Path::toString() const | |||
| return s.toUTF8(); | |||
| } | |||
| void Path::restoreFromString (const String& stringVersion) | |||
| void Path::restoreFromString (StringRef stringVersion) | |||
| { | |||
| clear(); | |||
| setUsingNonZeroWinding (true); | |||
| String::CharPointerType t (stringVersion.getCharPointer()); | |||
| String::CharPointerType t (stringVersion.text); | |||
| juce_wchar marker = 'm'; | |||
| int numValues = 2; | |||
| float values [6]; | |||
| @@ -740,7 +740,7 @@ public: | |||
| /** Restores this path from a string that was created with the toString() method. | |||
| @see toString() | |||
| */ | |||
| void restoreFromString (const String& stringVersion); | |||
| void restoreFromString (StringRef stringVersion); | |||
| private: | |||
| @@ -25,20 +25,21 @@ | |||
| class CodeDocumentLine | |||
| { | |||
| public: | |||
| CodeDocumentLine (const String::CharPointerType l, | |||
| CodeDocumentLine (const String::CharPointerType startOfLine, | |||
| const String::CharPointerType endOfLine, | |||
| const int lineLen, | |||
| const int numNewLineChars, | |||
| const int startInFile) | |||
| : line (l, (size_t) lineLen), | |||
| : line (startOfLine, endOfLine), | |||
| lineStartInFile (startInFile), | |||
| lineLength (lineLen), | |||
| lineLengthWithoutNewLines (lineLen - numNewLineChars) | |||
| { | |||
| } | |||
| static void createLines (Array <CodeDocumentLine*>& newLines, const String& text) | |||
| static void createLines (Array<CodeDocumentLine*>& newLines, StringRef text) | |||
| { | |||
| String::CharPointerType t (text.getCharPointer()); | |||
| String::CharPointerType t (text.text); | |||
| int charNumInFile = 0; | |||
| bool finished = false; | |||
| @@ -84,7 +85,7 @@ public: | |||
| } | |||
| } | |||
| newLines.add (new CodeDocumentLine (startOfLine, lineLength, | |||
| newLines.add (new CodeDocumentLine (startOfLine, t, lineLength, | |||
| numNewLineChars, startOfLineInFile)); | |||
| } | |||
| @@ -791,7 +792,8 @@ void CodeDocument::checkLastLineStatus() | |||
| if (lastLine != nullptr && lastLine->endsWithLineBreak()) | |||
| { | |||
| // check that there's an empty line at the end if the preceding one ends in a newline.. | |||
| lines.add (new CodeDocumentLine (String::empty.getCharPointer(), 0, 0, lastLine->lineStartInFile + lastLine->lineLength)); | |||
| lines.add (new CodeDocumentLine (StringRef(), StringRef(), 0, 0, | |||
| lastLine->lineStartInFile + lastLine->lineLength)); | |||
| } | |||
| } | |||
| @@ -227,9 +227,9 @@ private: | |||
| namespace CodeEditorHelpers | |||
| { | |||
| static int findFirstNonWhitespaceChar (const String& line) noexcept | |||
| static int findFirstNonWhitespaceChar (StringRef line) noexcept | |||
| { | |||
| String::CharPointerType t (line.getCharPointer()); | |||
| String::CharPointerType t (line.text); | |||
| int i = 0; | |||
| while (! t.isEmpty()) | |||
| @@ -1418,7 +1418,8 @@ String CodeEditorComponent::getTabString (const int numSpaces) const | |||
| int CodeEditorComponent::indexToColumn (int lineNum, int index) const noexcept | |||
| { | |||
| String::CharPointerType t (document.getLine (lineNum).getCharPointer()); | |||
| const String line (document.getLine (lineNum)); | |||
| String::CharPointerType t (line.getCharPointer()); | |||
| int col = 0; | |||
| for (int i = 0; i < index; ++i) | |||
| @@ -1440,7 +1441,8 @@ int CodeEditorComponent::indexToColumn (int lineNum, int index) const noexcept | |||
| int CodeEditorComponent::columnToIndex (int lineNum, int column) const noexcept | |||
| { | |||
| String::CharPointerType t (document.getLine (lineNum).getCharPointer()); | |||
| const String line (document.getLine (lineNum)); | |||
| String::CharPointerType t (line.getCharPointer()); | |||
| int i = 0, col = 0; | |||