@@ -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; | |||