diff --git a/include/ArduinoJson/Internals/JsonParser.hpp b/include/ArduinoJson/Internals/JsonParser.hpp index b423978a..be21b385 100644 --- a/include/ArduinoJson/Internals/JsonParser.hpp +++ b/include/ArduinoJson/Internals/JsonParser.hpp @@ -22,6 +22,7 @@ class JsonParser { bool isEnd() { return *_ptr == '\0'; } bool skip(char charToSkip); + bool skip(const char *wordToSkip); void skipSpaces(); void parseAnythingTo(JsonValue &destination); diff --git a/scripts/run-tests.sh b/scripts/run-tests.sh new file mode 100644 index 00000000..a41e83a8 --- /dev/null +++ b/scripts/run-tests.sh @@ -0,0 +1,44 @@ +#!/bin/bash + +FILE=../bin/ArduinoJsonTests.exe +MD5="" + +file_changed() { + [[ ! -f "$FILE" ]] && return 1 + NEW_MD5=$(md5sum $FILE) + [[ "$MD5" == "$NEW_MD5" ]] && return 1 + MD5=$NEW_MD5 + return 0 +} + +test_succeed() { + echo -en "\007"{,} +} + +test_failed() { + echo -en "\007"{,,,,,,,,,,,} +} + +run_tests() { + $FILE + case $? in + 0) + test_succeed + ;; + 1) + test_failed + ;; + esac +} + +while true +do + if file_changed + then + run_tests + else + sleep 2 + fi +done + + diff --git a/src/Arduino/Print.cpp b/src/Arduino/Print.cpp index 877447d7..6525f04a 100644 --- a/src/Arduino/Print.cpp +++ b/src/Arduino/Print.cpp @@ -19,7 +19,7 @@ size_t Print::print(const char s[]) { size_t Print::print(double value, int digits) { char tmp[32]; - sprintf(tmp, "%.*g", digits + 1, value); + sprintf(tmp, "%.*f", digits, value); return print(tmp); } diff --git a/src/Internals/CompactJsonWriter.cpp b/src/Internals/CompactJsonWriter.cpp deleted file mode 100644 index 587496b3..00000000 --- a/src/Internals/CompactJsonWriter.cpp +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright Benoit Blanchon 2014 -// MIT License -// -// Arduino JSON library -// https://github.com/bblanchon/ArduinoJson - -#include "ArduinoJson/Internals/CompactJsonWriter.hpp" diff --git a/src/Internals/JsonParser.cpp b/src/Internals/JsonParser.cpp index 70c5f98d..1df73876 100644 --- a/src/Internals/JsonParser.cpp +++ b/src/Internals/JsonParser.cpp @@ -30,6 +30,15 @@ bool JsonParser::skip(char charToSkip) { return true; } +bool JsonParser::skip(const char *wordToSkip) { + const char *charToSkip = wordToSkip; + while (*charToSkip && *_ptr == *charToSkip) { + charToSkip++; + _ptr++; + } + return *charToSkip == '\0'; +} + void JsonParser::parseAnythingTo(JsonValue &destination) { skipSpaces(); @@ -74,9 +83,9 @@ void JsonParser::parseAnythingTo(JsonValue &destination) { } JsonArray &JsonParser::parseArray() { - skip('['); + if (!skip('[')) return JsonArray::invalid(); // missing opening bracket - if (isEnd()) return JsonArray::invalid(); + if (isEnd()) return JsonArray::invalid(); // end of stream JsonArray &array = _buffer->createArray(); if (skip(']')) return array; // empty array @@ -96,13 +105,10 @@ JsonArray &JsonParser::parseArray() { void JsonParser::parseBooleanTo(JsonValue &destination) { bool value = *_ptr == 't'; - // TODO: bug if string ends here !!! - - _ptr += value ? 4 : 5; - // 4 = strlen("true") - // 5 = strlen("false"); - - destination = value; + if (skip(value ? "true" : "false")) + destination = value; + else + destination = JsonValue::invalid(); } void JsonParser::parseNumberTo(JsonValue &destination) { @@ -111,9 +117,9 @@ void JsonParser::parseNumberTo(JsonValue &destination) { if (*endOfLong == '.') { // stopped on a decimal separator - double douleValue = strtod(_ptr, &_ptr); + double doubleValue = strtod(_ptr, &_ptr); int decimals = _ptr - endOfLong - 1; - destination.set(douleValue, decimals); + destination.set(doubleValue, decimals); } else { _ptr = endOfLong; destination = longValue; @@ -121,13 +127,14 @@ void JsonParser::parseNumberTo(JsonValue &destination) { } void JsonParser::parseNullTo(JsonValue &destination) { - _ptr += 4; // strlen("null") - - destination = static_cast(NULL); + if (skip("null")) + destination = static_cast(NULL); + else + destination = JsonValue::invalid(); } JsonObject &JsonParser::parseObject() { - skip('{'); + if (!skip('{')) return JsonObject::invalid(); // missing opening brace if (isEnd()) return JsonObject::invalid(); // premature ending diff --git a/src/Internals/PrettyJsonWriter.cpp b/src/Internals/PrettyJsonWriter.cpp deleted file mode 100644 index b6a03812..00000000 --- a/src/Internals/PrettyJsonWriter.cpp +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright Benoit Blanchon 2014 -// MIT License -// -// Arduino JSON library -// https://github.com/bblanchon/ArduinoJson - -#include "ArduinoJson/Internals/PrettyJsonWriter.hpp" diff --git a/test/IntegrationTests.cpp b/test/IntegrationTests.cpp new file mode 100644 index 00000000..d0dd793d --- /dev/null +++ b/test/IntegrationTests.cpp @@ -0,0 +1,100 @@ +// Copyright Benoit Blanchon 2014 +// MIT License +// +// Arduino JSON library +// https://github.com/bblanchon/ArduinoJson + +#include +#include +#include +#include + +using namespace ArduinoJson; + +class IntegrationTests : public testing::TestWithParam { + protected: + virtual void SetUp() { + _input = GetParam(); + strcpy(inputBuffer, _input); + } + + const char* _input; + char inputBuffer[10000]; + char outputBuffer[10000]; + char intermediateBuffer[10000]; + StaticJsonBuffer<10000> json; +}; + +TEST_P(IntegrationTests, ParseThenPrint) { + json.parseObject(inputBuffer).printTo(outputBuffer, sizeof(outputBuffer)); + ASSERT_STREQ(_input, outputBuffer); +} + +TEST_P(IntegrationTests, ParseThenPrettyPrintThenParseThenPrint) { + json.parseObject(inputBuffer) + .prettyPrintTo(intermediateBuffer, sizeof(intermediateBuffer)); + json.clear(); + json.parseObject(intermediateBuffer) + .printTo(outputBuffer, sizeof(outputBuffer)); + ASSERT_STREQ(_input, outputBuffer); +} + +INSTANTIATE_TEST_CASE_P( + OpenWeatherMap, IntegrationTests, + testing::Values( + "{\"coord\":{\"lon\":145.77,\"lat\":-16.92},\"sys\":{\"type\":1,\"id\":" + "8166,\"message\":0.1222,\"country\":\"AU\",\"sunrise\":1414784325," + "\"sunset\":1414830137},\"weather\":[{\"id\":801,\"main\":\"Clouds\"," + "\"description\":\"few clouds\",\"icon\":\"02n\"}],\"base\":\"cmc " + "stations\",\"main\":{\"temp\":296.15,\"pressure\":1014,\"humidity\":" + "83,\"temp_min\":296.15,\"temp_max\":296.15},\"wind\":{\"speed\":2.22," + "\"deg\":114.501},\"clouds\":{\"all\":20},\"dt\":1414846800,\"id\":" + "2172797,\"name\":\"Cairns\",\"cod\":200}")); + +INSTANTIATE_TEST_CASE_P( + YahooQueryLanguage, IntegrationTests, + testing::Values( + "{\"query\":{\"count\":40,\"created\":\"2014-11-01T14:16:49Z\"," + "\"lang\":\"fr-FR\",\"results\":{\"item\":[{\"title\":\"Burkina army " + "backs Zida as interim leader\"},{\"title\":\"British jets intercept " + "Russian bombers\"},{\"title\":\"Doubts chip away at nation's most " + "trusted agencies\"},{\"title\":\"Cruise ship stuck off Norway, no " + "damage\"},{\"title\":\"U.S. military launches 10 air strikes in " + "Syria, Iraq\"},{\"title\":\"Blackout hits Bangladesh as line from " + "India fails\"},{\"title\":\"Burkina Faso president in Ivory Coast " + "after ouster\"},{\"title\":\"Kurds in Turkey rally to back city " + "besieged by IS\"},{\"title\":\"A majority of Scots would vote for " + "independence now:poll\"},{\"title\":\"Tunisia elections possible " + "model for region\"},{\"title\":\"Islamic State kills 85 more members " + "of Iraqi tribe\"},{\"title\":\"Iraqi officials:IS extremists line " + "up, kill 50\"},{\"title\":\"Burkina Faso army backs presidential " + "guard official to lead transition\"},{\"title\":\"Kurdish peshmerga " + "arrive with weapons in Syria's Kobani\"},{\"title\":\"Driver sought " + "in crash that killed 3 on Halloween\"},{\"title\":\"Ex-Marine arrives " + "in US after release from Mexico jail\"},{\"title\":\"UN panel " + "scrambling to finish climate report\"},{\"title\":\"Investigators, " + "Branson go to spacecraft crash site\"},{\"title\":\"Soldiers vie for " + "power after Burkina Faso president quits\"},{\"title\":\"For a man " + "without a party, turnout is big test\"},{\"title\":\"'We just had a " + "hunch':US marshals nab Eric Frein\"},{\"title\":\"Boko Haram leader " + "threatens to kill German hostage\"},{\"title\":\"Nurse free to move " + "about as restrictions eased\"},{\"title\":\"Former Burkina president " + "Compaore arrives in Ivory Coast:sources\"},{\"title\":\"Libyan port " + "rebel leader refuses to hand over oil ports to rival " + "group\"},{\"title\":\"Iraqi peshmerga fighters prepare for Syria " + "battle\"},{\"title\":\"1 Dem Senate candidate welcoming Obama's " + "help\"},{\"title\":\"Bikers cancel party after police recover " + "bar\"},{\"title\":\"New question in Texas:Can Davis survive " + "defeat?\"},{\"title\":\"Ukraine rebels to hold election, despite " + "criticism\"},{\"title\":\"Iraqi officials say Islamic State group " + "lines up, kills 50 tribesmen, women in Anbar " + "province\"},{\"title\":\"James rebounds, leads Cavaliers past " + "Bulls\"},{\"title\":\"UK warns travelers they could be terror " + "targets\"},{\"title\":\"Hello Kitty celebrates 40th " + "birthday\"},{\"title\":\"A look at people killed during space " + "missions\"},{\"title\":\"Nigeria's purported Boko Haram leader says " + "has 'married off' girls:AFP\"},{\"title\":\"Mexico orders immediate " + "release of Marine veteran\"},{\"title\":\"As election closes in, " + "Obama on center stage\"},{\"title\":\"Body of Zambian president " + "arrives home\"},{\"title\":\"South Africa arrests 2 Vietnamese for " + "poaching\"}]}}}")); diff --git a/test/JsonParser_Array_Tests.cpp b/test/JsonParser_Array_Tests.cpp index db3ef8a2..64f8b889 100644 --- a/test/JsonParser_Array_Tests.cpp +++ b/test/JsonParser_Array_Tests.cpp @@ -58,9 +58,13 @@ TEST_F(JsonParser_Array_Tests, EmptyArray) { sizeMustBe(0); } +TEST_F(JsonParser_Array_Tests, MissingOpeningBracket) { + whenInputIs("]"); + parseMustFail(); +} + TEST_F(JsonParser_Array_Tests, ArrayWithNoEnd) { whenInputIs("["); - parseMustFail(); } @@ -139,6 +143,21 @@ TEST_F(JsonParser_Array_Tests, TwoNulls) { secondElementMustBe(nullCharPtr); } +TEST_F(JsonParser_Array_Tests, IncompleteNull) { + whenInputIs("[nul!]"); + parseMustFail(); +} + +TEST_F(JsonParser_Array_Tests, IncompleteTrue) { + whenInputIs("[tru!]"); + parseMustFail(); +} + +TEST_F(JsonParser_Array_Tests, IncompleteFalse) { + whenInputIs("[fals!]"); + parseMustFail(); +} + TEST_F(JsonParser_Array_Tests, TwoStrings) { whenInputIs("[\"hello\",\"world\"]"); diff --git a/test/JsonParser_Object_Tests.cpp b/test/JsonParser_Object_Tests.cpp index 95403610..5d25c536 100644 --- a/test/JsonParser_Object_Tests.cpp +++ b/test/JsonParser_Object_Tests.cpp @@ -45,22 +45,24 @@ TEST_F(JsonParser_Object_Test, EmptyObject) { sizeMustBe(0); } +TEST_F(JsonParser_Object_Test, MissingOpeningBrace) { + whenInputIs("}"); + parseMustFail(); +} + TEST_F(JsonParser_Object_Test, MissingClosingBrace) { whenInputIs("{"); parseMustFail(); - sizeMustBe(0); } TEST_F(JsonParser_Object_Test, MissingColonAndValue) { whenInputIs("{\"key\"}"); parseMustFail(); - sizeMustBe(0); } TEST_F(JsonParser_Object_Test, MissingQuotesAndColonAndValue) { whenInputIs("{key}"); parseMustFail(); - sizeMustBe(0); } TEST_F(JsonParser_Object_Test, OneString) {