Permalink
Browse files

Fixed a bug writing doubles to XML and JSON

  • Loading branch information...
tpoole committed Feb 11, 2019
1 parent 66691fc commit 865eabd4347d9a054a1d14edc1b67eeed171b71f
@@ -352,8 +352,8 @@ struct JSONFormatter

if (juce_isfinite (d))
{
String doubleString (d, maximumDecimalPlaces);
out << doubleString.substring (0, (int) CharacterFunctions::findLengthWithoutTrailingZeros (doubleString.getCharPointer()));
String doubleString (d, maximumDecimalPlaces, true);
out << minimiseLengthOfFloatString (doubleString);
}
else
{
@@ -627,31 +627,52 @@ class JSONTests : public UnitTest

void runTest() override
{
beginTest ("JSON");
Random r = getRandom();

expect (JSON::parse (String()) == var());
expect (JSON::parse ("{}").isObject());
expect (JSON::parse ("[]").isArray());
expect (JSON::parse ("[ 1234 ]")[0].isInt());
expect (JSON::parse ("[ 12345678901234 ]")[0].isInt64());
expect (JSON::parse ("[ 1.123e3 ]")[0].isDouble());
expect (JSON::parse ("[ -1234]")[0].isInt());
expect (JSON::parse ("[-12345678901234]")[0].isInt64());
expect (JSON::parse ("[-1.123e3]")[0].isDouble());

for (int i = 100; --i >= 0;)
{
var v;
beginTest ("JSON");

if (i > 0)
v = createRandomVar (r, 0);
Random r = getRandom();

const bool oneLine = r.nextBool();
String asString (JSON::toString (v, oneLine));
var parsed = JSON::parse ("[" + asString + "]")[0];
String parsedString (JSON::toString (parsed, oneLine));
expect (asString.isNotEmpty() && parsedString == asString);
expect (JSON::parse (String()) == var());
expect (JSON::parse ("{}").isObject());
expect (JSON::parse ("[]").isArray());
expect (JSON::parse ("[ 1234 ]")[0].isInt());
expect (JSON::parse ("[ 12345678901234 ]")[0].isInt64());
expect (JSON::parse ("[ 1.123e3 ]")[0].isDouble());
expect (JSON::parse ("[ -1234]")[0].isInt());
expect (JSON::parse ("[-12345678901234]")[0].isInt64());
expect (JSON::parse ("[-1.123e3]")[0].isDouble());

for (int i = 100; --i >= 0;)
{
var v;

if (i > 0)
v = createRandomVar (r, 0);

const bool oneLine = r.nextBool();
String asString (JSON::toString (v, oneLine));
var parsed = JSON::parse ("[" + asString + "]")[0];
String parsedString (JSON::toString (parsed, oneLine));
expect (asString.isNotEmpty() && parsedString == asString);
}
}

{
beginTest ("Float formatting");

std::map<double, String> tests;
tests[1] = "1";
tests[1.1] = "1.1";
tests[1.01] = "1.01";
tests[0.76378] = "7.6378e-1";
tests[-10] = "-1e1";
tests[10.01] = "1.001e1";
tests[0.0123] = "1.23e-2";
tests[-3.7e-27] = "-3.7e-27";
tests[1e+40] = "1e40";

for (auto& test : tests)
expectEquals (JSON::toString (test.first), test.second);
}
}
};
@@ -92,12 +92,13 @@ class JUCE_API JSON
/** Returns a string which contains a JSON-formatted representation of the var object.
If allOnOneLine is true, the result will be compacted into a single line of text
with no carriage-returns. If false, it will be laid-out in a more human-readable format.
The maximumDecimalPlaces parameter determines the precision of floating point numbers.
The maximumDecimalPlaces parameter determines the precision of floating point numbers
in scientific notation.
@see writeToStream
*/
static String toString (const var& objectToFormat,
bool allOnOneLine = false,
int maximumDecimalPlaces = 20);
int maximumDecimalPlaces = 15);

/** Parses a string that was created with the toString() method.
This is slightly different to the parse() methods because they will reject primitive
@@ -132,9 +132,6 @@
#include "files/juce_FileOutputStream.cpp"
#include "files/juce_FileSearchPath.cpp"
#include "files/juce_TemporaryFile.cpp"
#include "javascript/juce_JSON.cpp"
#include "javascript/juce_Javascript.cpp"
#include "containers/juce_DynamicObject.cpp"
#include "logging/juce_FileLogger.cpp"
#include "logging/juce_Logger.cpp"
#include "maths/juce_BigInteger.cpp"
@@ -175,6 +172,9 @@
#include "time/juce_RelativeTime.cpp"
#include "time/juce_Time.cpp"
#include "unit_tests/juce_UnitTest.cpp"
#include "javascript/juce_JSON.cpp"
#include "javascript/juce_Javascript.cpp"
#include "containers/juce_DynamicObject.cpp"
#include "xml/juce_XmlDocument.cpp"
#include "xml/juce_XmlElement.cpp"
#include "zip/juce_GZIPDecompressorInputStream.cpp"
@@ -413,35 +413,6 @@ class JUCE_API CharacterFunctions
return readDoubleValue (text);
}

/** If the input is a string representation of a floating-point number, this will
find the length of the string without any trailing zeros.
*/
template <typename CharPointerType>
static size_t findLengthWithoutTrailingZeros (CharPointerType text)
{
auto start = text;
auto end = text + ((int) text.length());

for (auto e = end; e > start + 1; --e)
{
auto lastChar = *(e - 1);

if (lastChar != '0')
{
if (lastChar == '.')
return (size_t) (e + 1 - start);

for (auto s = start; s < e; ++s)
if (*s == '.')
return (size_t) (e - start);

break;
}
}

return (size_t) (end - start);
}

//==============================================================================
/** Parses a character string, to read an integer value. */
template <typename IntType, typename CharPointerType>
Oops, something went wrong.

0 comments on commit 865eabd

Please sign in to comment.