Compare commits

...

24 Commits
1.1.0 ... 1.2.0

Author SHA1 Message Date
Christopher Dunn
4ce4bb8404 Merge pull request #124 from cdunn2001/assign-with-comments
1.2.0

 `operator=()` (which already performed a deep-copy) now includes comments. This change is probably harmless in all practical cases. But just in case, we bump the minor version.

Address #47.
2015-01-20 12:49:51 -06:00
Christopher Dunn
2cd0f4ec21 1.2.0 <- 1.1.1
`operator=()` (which already performed a deep-copy) now includes
comments. The change is probably harmless in all practical cases.
2015-01-20 12:44:51 -06:00
Christopher Dunn
836f0fb863 fix comments before several types
tests pass
2015-01-20 12:23:44 -06:00
Christopher Dunn
37644abd77 test comment before several types
* array
* double
* string
* true
* false
* null
2015-01-20 12:23:18 -06:00
Christopher Dunn
66eb72f121 use SwapPayload() to retain comments
All tests pass, but we might be missing coverage.

issue #47
2015-01-20 12:07:01 -06:00
Christopher Dunn
94b0297dc5 Revert "consider these as binary, so git will not alter line-endings"
This reverts commit 8f3aa220db.

We will find a better fix for #116. In the meantime, we want to see
diffs for changes to test-data.
2015-01-20 12:06:12 -06:00
Christopher Dunn
55db3c3cb2 Merge pull request #118 from datadiode/47_fix_value_swap
swap comments too

* Changed `operator=` to exclude start/limit, which should never have been added.
* Changed `swap` to include comments. Hmm. That affects efficiency (but *not* for `operator=`) and probably nothing else in practice.

- issue #47
2015-01-18 11:31:47 -06:00
datadiode
c07ef37904 https://github.com/open-source-parsers/jsoncpp/issues/47 2015-01-18 10:05:25 +01:00
Christopher Dunn
62ab94ddd3 Merge pull request #117 from datadiode/integration
Simplify Reader::decodeNumber() / Remove unused functions
2015-01-17 08:10:59 -06:00
datadiode
09d352ac13 Remove unused functions 2015-01-17 13:26:23 +01:00
datadiode
50753bb808 Simplify Reader::decodeNumber() 2015-01-17 13:21:42 +01:00
Christopher Dunn
8f3aa220db consider these as binary, so git will not alter line-endings
issue #116
2015-01-16 16:29:07 -06:00
Christopher Dunn
73e127892e Merge branch 'fix-fail31' 2015-01-16 15:10:56 -06:00
Christopher Dunn
4997dfb8af 1.1.1 <- 1.1.0
slight change to fail on a bad float
2015-01-16 15:09:54 -06:00
datadiode
c1441ef5e0 stricter float parsing
fixes `test/jsonchecker/fail31.json`
(issue #113)
2015-01-16 15:05:12 -06:00
Christopher Dunn
e0bfb45000 Merge branch 'py3/2' 2015-01-16 14:53:22 -06:00
Christopher Dunn
4bc311503c just in case 2015-01-16 14:53:04 -06:00
Christopher Dunn
cd140b5141 py2 and py3 2015-01-16 14:52:56 -06:00
datadiode
01aee4a0dc Fix Python test scripts for Python 3 and Windows 2015-01-16 09:57:42 -06:00
Christopher Dunn
59a01652ab Merge pull request #114 from Gachapen/fix_cmake_output_dir
CMake: Remove set(CMAKE_*_OUTPUT_DIRECTORY)
2015-01-15 20:17:34 -06:00
Magnus Bjerke Vik
8371a4337c CMake: Remove set(CMAKE_*_OUTPUT_DIRECTORY)
With set(CMAKE_*_OUTPUT_DIRECTORY) when using jsoncpp as a sub project,
the parent project's executables and libraries will also be outputed to
jsoncpp's directory. By removing this, it is up to the parent projects
to decide where to put their and jsoncpp's executables and libraries.
2015-01-15 20:16:54 -06:00
Christopher Dunn
dc2e1c98b9 Merge pull request #111 from open-source-parsers/quotes-spaces-fixed
Quotes spaces fixed
2015-01-09 22:36:40 -06:00
Christopher Dunn
d98b5f4230 quote spaces in commands for Windows
See comments at:
    1a4dc3a888
2015-01-09 22:32:10 -06:00
Christopher Dunn
4ca9d25ccc Revert "Merge pull request #108 from open-source-parsers/quote-spaces"
This reverts commit dfc5f879c1, reversing
changes made to 0f6884f771.
2015-01-09 22:28:20 -06:00
14 changed files with 117 additions and 85 deletions

2
.gitignore vendored
View File

@@ -10,4 +10,4 @@
/libs/
/doc/doxyfile
/dist/
/include/json/version.h
#/include/json/version.h

View File

@@ -31,16 +31,6 @@ SET(PACKAGE_INSTALL_DIR lib${LIB_SUFFIX}/cmake
CACHE PATH "Install dir for cmake package config files")
MARK_AS_ADVANCED( RUNTIME_INSTALL_DIR ARCHIVE_INSTALL_DIR INCLUDE_INSTALL_DIR PACKAGE_INSTALL_DIR )
# This ensures shared DLL are in the same dir as executable on Windows.
# Put all executables / libraries are in a project global directory.
SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib
CACHE PATH "Single directory for all static libraries.")
SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib
CACHE PATH "Single directory for all dynamic libraries on Unix.")
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin
CACHE PATH "Single directory for all executable and dynamic libraries on Windows.")
MARK_AS_ADVANCED( CMAKE_RUNTIME_OUTPUT_DIRECTORY CMAKE_LIBRARY_OUTPUT_DIRECTORY CMAKE_ARCHIVE_OUTPUT_DIRECTORY )
# Set variable named ${VAR_NAME} to value ${VALUE}
FUNCTION(set_using_dynamic_name VAR_NAME VALUE)
SET( "${VAR_NAME}" "${VALUE}" PARENT_SCOPE)

View File

@@ -187,7 +187,6 @@ private:
typedef std::deque<ErrorInfo> Errors;
bool expectToken(TokenType type, Token& token, const char* message);
bool readToken(Token& token);
void skipSpaces();
bool match(Location pattern, int patternLength);

View File

@@ -235,25 +235,26 @@ Json::Value obj_value(Json::objectValue); // {}
Value(const CppTL::ConstString& value);
#endif
Value(bool value);
/// Deep copy.
Value(const Value& other);
~Value();
// Deep copy, then swap(other).
Value& operator=(Value other);
/// Swap values.
/// \note Currently, comments are intentionally not swapped, for
/// both logic and efficiency.
/// Swap everything.
void swap(Value& other);
/// Swap values but leave comments and source offsets in place.
void swapPayload(Value& other);
ValueType type() const;
/// Compare payload only, not comments etc.
bool operator<(const Value& other) const;
bool operator<=(const Value& other) const;
bool operator>=(const Value& other) const;
bool operator>(const Value& other) const;
bool operator==(const Value& other) const;
bool operator!=(const Value& other) const;
int compare(const Value& other) const;
const char* asCString() const;

View File

@@ -4,9 +4,9 @@
#ifndef JSON_VERSION_H_INCLUDED
# define JSON_VERSION_H_INCLUDED
# define JSONCPP_VERSION_STRING "1.1.0"
# define JSONCPP_VERSION_STRING "1.2.0"
# define JSONCPP_VERSION_MAJOR 1
# define JSONCPP_VERSION_MINOR 1
# define JSONCPP_VERSION_MINOR 2
# define JSONCPP_VERSION_PATCH 0
# define JSONCPP_VERSION_QUALIFIER
# define JSONCPP_VERSION_HEXA ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | (JSONCPP_VERSION_PATCH << 8))

View File

@@ -47,23 +47,6 @@ Features Features::strictMode() {
// Implementation of class Reader
// ////////////////////////////////
static inline bool in(Reader::Char c,
Reader::Char c1,
Reader::Char c2,
Reader::Char c3,
Reader::Char c4) {
return c == c1 || c == c2 || c == c3 || c == c4;
}
static inline bool in(Reader::Char c,
Reader::Char c1,
Reader::Char c2,
Reader::Char c3,
Reader::Char c4,
Reader::Char c5) {
return c == c1 || c == c2 || c == c3 || c == c4 || c == c5;
}
static bool containsNewLine(Reader::Location begin, Reader::Location end) {
for (; begin < end; ++begin)
if (*begin == '\n' || *begin == '\r')
@@ -180,26 +163,36 @@ bool Reader::readValue() {
successful = decodeString(token);
break;
case tokenTrue:
currentValue() = true;
{
Value v(true);
currentValue().swapPayload(v);
currentValue().setOffsetStart(token.start_ - begin_);
currentValue().setOffsetLimit(token.end_ - begin_);
}
break;
case tokenFalse:
currentValue() = false;
{
Value v(false);
currentValue().swapPayload(v);
currentValue().setOffsetStart(token.start_ - begin_);
currentValue().setOffsetLimit(token.end_ - begin_);
}
break;
case tokenNull:
currentValue() = Value();
{
Value v;
currentValue().swapPayload(v);
currentValue().setOffsetStart(token.start_ - begin_);
currentValue().setOffsetLimit(token.end_ - begin_);
}
break;
case tokenArraySeparator:
if (features_.allowDroppedNullPlaceholders_) {
// "Un-read" the current token and mark the current value as a null
// token.
current_--;
currentValue() = Value();
Value v;
currentValue().swapPayload(v);
currentValue().setOffsetStart(current_ - begin_ - 1);
currentValue().setOffsetLimit(current_ - begin_);
break;
@@ -229,13 +222,6 @@ void Reader::skipCommentTokens(Token& token) {
}
}
bool Reader::expectToken(TokenType type, Token& token, const char* message) {
readToken(token);
if (token.type_ != type)
return addError(message, token);
return true;
}
bool Reader::readToken(Token& token) {
skipSpaces();
token.start_ = current_;
@@ -381,11 +367,24 @@ bool Reader::readCppStyleComment() {
}
void Reader::readNumber() {
while (current_ != end_) {
if (!(*current_ >= '0' && *current_ <= '9') &&
!in(*current_, '.', 'e', 'E', '+', '-'))
break;
++current_;
const char *p = current_;
char c = '0'; // stopgap for already consumed character
// integral part
while (c >= '0' && c <= '9')
c = (current_ = p) < end_ ? *p++ : 0;
// fractional part
if (c == '.') {
c = (current_ = p) < end_ ? *p++ : 0;
while (c >= '0' && c <= '9')
c = (current_ = p) < end_ ? *p++ : 0;
}
// exponential part
if (c == 'e' || c == 'E') {
c = (current_ = p) < end_ ? *p++ : 0;
if (c == '+' || c == '-')
c = (current_ = p) < end_ ? *p++ : 0;
while (c >= '0' && c <= '9')
c = (current_ = p) < end_ ? *p++ : 0;
}
}
@@ -404,7 +403,8 @@ bool Reader::readString() {
bool Reader::readObject(Token& tokenStart) {
Token tokenName;
std::string name;
currentValue() = Value(objectValue);
Value init(objectValue);
currentValue().swapPayload(init);
currentValue().setOffsetStart(tokenStart.start_ - begin_);
while (readToken(tokenName)) {
bool initialTokenOk = true;
@@ -457,7 +457,8 @@ bool Reader::readObject(Token& tokenStart) {
}
bool Reader::readArray(Token& tokenStart) {
currentValue() = Value(arrayValue);
Value init(arrayValue);
currentValue().swapPayload(init);
currentValue().setOffsetStart(tokenStart.start_ - begin_);
skipSpaces();
if (*current_ == ']') // empty array
@@ -497,20 +498,13 @@ bool Reader::decodeNumber(Token& token) {
Value decoded;
if (!decodeNumber(token, decoded))
return false;
currentValue() = decoded;
currentValue().swapPayload(decoded);
currentValue().setOffsetStart(token.start_ - begin_);
currentValue().setOffsetLimit(token.end_ - begin_);
return true;
}
bool Reader::decodeNumber(Token& token, Value& decoded) {
bool isDouble = false;
for (Location inspect = token.start_; inspect != token.end_; ++inspect) {
isDouble = isDouble || in(*inspect, '.', 'e', 'E', '+') ||
(*inspect == '-' && inspect != token.start_);
}
if (isDouble)
return decodeDouble(token, decoded);
// Attempts to parse the number as an integer. If the number is
// larger than the maximum supported value of an integer then
// we decode the number as a double.
@@ -518,6 +512,7 @@ bool Reader::decodeNumber(Token& token, Value& decoded) {
bool isNegative = *current == '-';
if (isNegative)
++current;
// TODO: Help the compiler do the div and mod at compile time or get rid of them.
Value::LargestUInt maxIntegerValue =
isNegative ? Value::LargestUInt(-Value::minLargestInt)
: Value::maxLargestUInt;
@@ -526,9 +521,7 @@ bool Reader::decodeNumber(Token& token, Value& decoded) {
while (current < token.end_) {
Char c = *current++;
if (c < '0' || c > '9')
return addError("'" + std::string(token.start_, token.end_) +
"' is not a number.",
token);
return decodeDouble(token, decoded);
Value::UInt digit(c - '0');
if (value >= threshold) {
// We've hit or exceeded the max value divided by 10 (rounded down). If
@@ -555,7 +548,7 @@ bool Reader::decodeDouble(Token& token) {
Value decoded;
if (!decodeDouble(token, decoded))
return false;
currentValue() = decoded;
currentValue().swapPayload(decoded);
currentValue().setOffsetStart(token.start_ - begin_);
currentValue().setOffsetLimit(token.end_ - begin_);
return true;
@@ -598,10 +591,11 @@ bool Reader::decodeDouble(Token& token, Value& decoded) {
}
bool Reader::decodeString(Token& token) {
std::string decoded;
if (!decodeString(token, decoded))
std::string decoded_string;
if (!decodeString(token, decoded_string))
return false;
currentValue() = decoded;
Value decoded(decoded_string);
currentValue().swapPayload(decoded);
currentValue().setOffsetStart(token.start_ - begin_);
currentValue().setOffsetLimit(token.end_ - begin_);
return true;

View File

@@ -410,7 +410,7 @@ Value& Value::operator=(Value other) {
return *this;
}
void Value::swap(Value& other) {
void Value::swapPayload(Value& other) {
ValueType temp = type_;
type_ = other.type_;
other.type_ = temp;
@@ -418,6 +418,11 @@ void Value::swap(Value& other) {
int temp2 = allocated_;
allocated_ = other.allocated_;
other.allocated_ = temp2;
}
void Value::swap(Value& other) {
swapPayload(other);
std::swap(comments_, other.comments_);
std::swap(start_, other.start_);
std::swap(limit_, other.limit_);
}

View File

@@ -1,4 +1,5 @@
.={}
// Comment for array
.test=[]
.test[0]={}
.test[0].a="aaa"

View File

@@ -1,5 +1,6 @@
{
"test":
// Comment for array
[
{ "a" : "aaa" }, // Comment for a
{ "b" : "bbb" }, // Comment for b

View File

@@ -11,4 +11,13 @@
// Multiline comment cpp-style
// Second line
.cpp-test.c=3
.cpp-test.d=4
// Comment before double
.cpp-test.d=4.1
// Comment before string
.cpp-test.e="e-string"
// Comment before true
.cpp-test.f=true
// Comment before false
.cpp-test.g=false
// Comment before null
.cpp-test.h=null

View File

@@ -12,6 +12,15 @@
// Multiline comment cpp-style
// Second line
"c" : 3,
"d" : 4
// Comment before double
"d" : 4.1,
// Comment before string
"e" : "e-string",
// Comment before true
"f" : true,
// Comment before false
"g" : false,
// Comment before null
"h" : null
}
}

View File

@@ -1,12 +1,30 @@
from __future__ import print_function
from __future__ import unicode_literals
from io import open
from glob import glob
import sys
import os
import pipes
import os.path
import optparse
VALGRIND_CMD = 'valgrind --tool=memcheck --leak-check=yes --undef-value-errors=yes '
def getStatusOutput(cmd):
"""
Return int, unicode (for both Python 2 and 3).
Note: os.popen().close() would return None for 0.
"""
pipe = os.popen(cmd)
process_output = pipe.read()
try:
# We have been using os.popen(). When we read() the result
# we get 'str' (bytes) in py2, and 'str' (unicode) in py3.
# Ugh! There must be a better way to handle this.
process_output = process_output.decode('utf-8')
except AttributeError:
pass # python3
status = pipe.close()
return status, process_output
def compareOutputs( expected, actual, message ):
expected = expected.strip().replace('\r','').split('\n')
actual = actual.strip().replace('\r','').split('\n')
@@ -34,7 +52,7 @@ def compareOutputs( expected, actual, message ):
def safeReadFile( path ):
try:
return file( path, 'rt' ).read()
return open( path, 'rt', encoding = 'utf-8' ).read()
except IOError as e:
return '<File "%s" is missing: %s>' % (path,e)
@@ -54,21 +72,20 @@ def runAllTests( jsontest_executable_path, input_dir = None,
is_json_checker_test = (input_path in test_jsonchecker) or expect_failure
print('TESTING:', input_path, end=' ')
options = is_json_checker_test and '--json-checker' or ''
pipe = os.popen( "%s%s %s %s" % (
cmd = '%s%s %s "%s"' % (
valgrind_path, jsontest_executable_path, options,
pipes.quote(input_path)))
process_output = pipe.read()
status = pipe.close()
input_path)
status, process_output = getStatusOutput(cmd)
if is_json_checker_test:
if expect_failure:
if status is None:
if not status:
print('FAILED')
failed_tests.append( (input_path, 'Parsing should have failed:\n%s' %
safeReadFile(input_path)) )
else:
print('OK')
else:
if status is not None:
if status:
print('FAILED')
failed_tests.append( (input_path, 'Parsing failed:\n' + process_output) )
else:
@@ -77,13 +94,13 @@ def runAllTests( jsontest_executable_path, input_dir = None,
base_path = os.path.splitext(input_path)[0]
actual_output = safeReadFile( base_path + '.actual' )
actual_rewrite_output = safeReadFile( base_path + '.actual-rewrite' )
file(base_path + '.process-output','wt').write( process_output )
open(base_path + '.process-output', 'wt', encoding = 'utf-8').write( process_output )
if status:
print('parsing failed')
failed_tests.append( (input_path, 'Parsing failed:\n' + process_output) )
else:
expected_output_path = os.path.splitext(input_path)[0] + '.expected'
expected_output = file( expected_output_path, 'rt' ).read()
expected_output = open( expected_output_path, 'rt', encoding = 'utf-8' ).read()
detail = ( compareOutputs( expected_output, actual_output, 'input' )
or compareOutputs( expected_output, actual_rewrite_output, 'rewrite' ) )
if detail:

View File

@@ -1,4 +1,6 @@
from __future__ import print_function
from __future__ import unicode_literals
from io import open
from glob import glob
import sys
import os
@@ -19,7 +21,11 @@ class TestProxy(object):
else:
cmd = []
cmd.extend( [self.test_exe_path, '--test-auto'] + options )
process = subprocess.Popen( cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT )
try:
process = subprocess.Popen( cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT )
except:
print(cmd)
raise
stdout = process.communicate()[0]
if process.returncode:
return False, stdout
@@ -31,7 +37,7 @@ def runAllTests( exe_path, use_valgrind=False ):
if not status:
print("Failed to obtain unit tests list:\n" + test_names, file=sys.stderr)
return 1
test_names = [name.strip() for name in test_names.strip().split('\n')]
test_names = [name.strip() for name in test_names.decode('utf-8').strip().split('\n')]
failures = []
for name in test_names:
print('TESTING %s:' % name, end=' ')

View File

@@ -1 +1 @@
1.1.0
1.2.0