Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  testParseJSON.cpp   Sprache: C

 
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 * vim: set ts=8 sts=2 et sw=2 tw=80:
 */

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


#include <limits>
#include <string.h>

#include "js/Array.h"  // JS::IsArrayObject
#include "js/Exception.h"
#include "js/friend/ErrorMessages.h"  // JSMSG_*
#include "js/JSON.h"
#include "js/MemoryFunctions.h"
#include "js/Printf.h"
#include "js/PropertyAndElement.h"  // JS_GetProperty
#include "jsapi-tests/tests.h"

using namespace js;

class AutoInflatedString {
  JSContext* const cx;
  char16_t* chars_;
  size_t length_;

 public:
  explicit AutoInflatedString(JSContext* cx)
      : cx(cx), chars_(nullptr), length_(0) {}
  ~AutoInflatedString() { JS_free(cx, chars_); }

  template <size_t N>
  void operator=(const char (&str)[N]) {
    length_ = N - 1;
    chars_ = InflateString(cx, str, length_);
    if (!chars_) {
      abort();
    }
  }

  void operator=(const char* str) {
    length_ = strlen(str);
    chars_ = InflateString(cx, str, length_);
    if (!chars_) {
      abort();
    }
  }

  const char16_t* chars() const { return chars_; }
  size_t length() const { return length_; }
};

BEGIN_TEST(testParseJSON_success) {
  // Primitives
  JS::RootedValue expected(cx);
  expected = JS::TrueValue();
  CHECK(TryParse(cx, "true", expected));

  expected = JS::FalseValue();
  CHECK(TryParse(cx, "false", expected));

  expected = JS::NullValue();
  CHECK(TryParse(cx, "null", expected));

  expected.setInt32(0);
  CHECK(TryParse(cx, "0", expected));

  expected.setInt32(1);
  CHECK(TryParse(cx, "1", expected));

  expected.setInt32(-1);
  CHECK(TryParse(cx, "-1", expected));

  expected.setDouble(1);
  CHECK(TryParse(cx, "1", expected));

  expected.setDouble(1.75);
  CHECK(TryParse(cx, "1.75", expected));

  expected.setDouble(9e9);
  CHECK(TryParse(cx, "9e9", expected));

  expected.setDouble(std::numeric_limits<double>::infinity());
  CHECK(TryParse(cx, "9e99999", expected));

  JS::Rooted<JSLinearString*> str(cx);

  const char16_t emptystr[] = {'\0'};
  str = js::NewStringCopyN<CanGC>(cx, emptystr, 0);
  CHECK(str);
  expected = JS::StringValue(str);
  CHECK(TryParse(cx, "\"\"", expected));

  const char16_t nullstr[] = {'\0'};
  str = NewString(cx, nullstr);
  CHECK(str);
  expected = JS::StringValue(str);
  CHECK(TryParse(cx, "\"\\u0000\"", expected));

  const char16_t backstr[] = {'\b'};
  str = NewString(cx, backstr);
  CHECK(str);
  expected = JS::StringValue(str);
  CHECK(TryParse(cx, "\"\\b\"", expected));
  CHECK(TryParse(cx, "\"\\u0008\"", expected));

  const char16_t newlinestr[] = {
      '\n',
  };
  str = NewString(cx, newlinestr);
  CHECK(str);
  expected = JS::StringValue(str);
  CHECK(TryParse(cx, "\"\\n\"", expected));
  CHECK(TryParse(cx, "\"\\u000A\"", expected));

  // Arrays
  JS::RootedValue v(cx), v2(cx);
  JS::RootedObject obj(cx);

  bool isArray;

  CHECK(Parse(cx, "[]", &v));
  CHECK(v.isObject());
  obj = &v.toObject();
  CHECK(JS::IsArrayObject(cx, obj, &isArray));
  CHECK(isArray);
  CHECK(JS_GetProperty(cx, obj, "length", &v2));
  CHECK(v2.isInt32(0));

  CHECK(Parse(cx, "[1]", &v));
  CHECK(v.isObject());
  obj = &v.toObject();
  CHECK(JS::IsArrayObject(cx, obj, &isArray));
  CHECK(isArray);
  CHECK(JS_GetProperty(cx, obj, "0", &v2));
  CHECK(v2.isInt32(1));
  CHECK(JS_GetProperty(cx, obj, "length", &v2));
  CHECK(v2.isInt32(1));

  // Objects
  CHECK(Parse(cx, "{}", &v));
  CHECK(v.isObject());
  obj = &v.toObject();
  CHECK(JS::IsArrayObject(cx, obj, &isArray));
  CHECK(!isArray);

  CHECK(Parse(cx, "{ \"f\": 17 }", &v));
  CHECK(v.isObject());
  obj = &v.toObject();
  CHECK(JS::IsArrayObject(cx, obj, &isArray));
  CHECK(!isArray);
  CHECK(JS_GetProperty(cx, obj, "f", &v2));
  CHECK(v2.isInt32(17));

  return true;
}

template <size_t N>
static JSLinearString* NewString(JSContext* cx, const char16_t (&chars)[N]) {
  return js::NewStringCopyN<CanGC>(cx, chars, N);
}

template <size_t N>
inline bool Parse(JSContext* cx, const char (&input)[N],
                  JS::MutableHandleValue vp) {
  AutoInflatedString str(cx);
  str = input;
  CHECK(JS_ParseJSON(cx, str.chars(), str.length(), vp));
  return true;
}

template <size_t N>
inline bool TryParse(JSContext* cx, const char (&input)[N],
                     JS::HandleValue expected) {
  AutoInflatedString str(cx);
  RootedValue v(cx);
  str = input;
  CHECK(JS_ParseJSON(cx, str.chars(), str.length(), &v));
  CHECK_SAME(v, expected);
  return true;
}
END_TEST(testParseJSON_success)

BEGIN_TEST(testParseJSON_error) {
  CHECK(Error(cx, "", 1, 1));
  CHECK(Error(cx, "\n", 2, 1));
  CHECK(Error(cx, "\r", 2, 1));
  CHECK(Error(cx, "\r\n", 2, 1));

  CHECK(Error(cx, "[", 1, 2));
  CHECK(Error(cx, "[,]", 1, 2));
  CHECK(Error(cx, "[1,]", 1, 4));
  CHECK(Error(cx, "{a:2}", 1, 2));
  CHECK(Error(cx, "{\"a\":2,}", 1, 8));
  CHECK(Error(cx, "]", 1, 1));
  CHECK(Error(cx, "\"", 1, 2));
  CHECK(Error(cx, "{]", 1, 2));
  CHECK(Error(cx, "[}", 1, 2));
  CHECK(Error(cx, "'wrongly-quoted string'", 1, 1));

  CHECK(Error(cx, "{\"a\":2 \n b:3}", 2, 2));
  CHECK(Error(cx, "\n[", 2, 2));
  CHECK(Error(cx, "\n[,]", 2, 2));
  CHECK(Error(cx, "\n[1,]", 2, 4));
  CHECK(Error(cx, "\n{a:2}", 2, 2));
  CHECK(Error(cx, "\n{\"a\":2,}", 2, 8));
  CHECK(Error(cx, "\n]", 2, 1));
  CHECK(Error(cx, "\"bad string\n\"", 1, 12));
  CHECK(Error(cx, "\r'wrongly-quoted string'", 2, 1));
  CHECK(Error(cx, "\n\"", 2, 2));
  CHECK(Error(cx, "\n{]", 2, 2));
  CHECK(Error(cx, "\n[}", 2, 2));
  CHECK(Error(cx, "{\"a\":[2,3],\n\"b\":,5,6}", 2, 5));

  CHECK(Error(cx, "{\"a\":2 \r b:3}", 2, 2));
  CHECK(Error(cx, "\r[", 2, 2));
  CHECK(Error(cx, "\r[,]", 2, 2));
  CHECK(Error(cx, "\r[1,]", 2, 4));
  CHECK(Error(cx, "\r{a:2}", 2, 2));
  CHECK(Error(cx, "\r{\"a\":2,}", 2, 8));
  CHECK(Error(cx, "\r]", 2, 1));
  CHECK(Error(cx, "\"bad string\r\"", 1, 12));
  CHECK(Error(cx, "\r'wrongly-quoted string'", 2, 1));
  CHECK(Error(cx, "\r\"", 2, 2));
  CHECK(Error(cx, "\r{]", 2, 2));
  CHECK(Error(cx, "\r[}", 2, 2));
  CHECK(Error(cx, "{\"a\":[2,3],\r\"b\":,5,6}", 2, 5));

  CHECK(Error(cx, "{\"a\":2 \r\n b:3}", 2, 2));
  CHECK(Error(cx, "\r\n[", 2, 2));
  CHECK(Error(cx, "\r\n[,]", 2, 2));
  CHECK(Error(cx, "\r\n[1,]", 2, 4));
  CHECK(Error(cx, "\r\n{a:2}", 2, 2));
  CHECK(Error(cx, "\r\n{\"a\":2,}", 2, 8));
  CHECK(Error(cx, "\r\n]", 2, 1));
  CHECK(Error(cx, "\"bad string\r\n\"", 1, 12));
  CHECK(Error(cx, "\r\n'wrongly-quoted string'", 2, 1));
  CHECK(Error(cx, "\r\n\"", 2, 2));
  CHECK(Error(cx, "\r\n{]", 2, 2));
  CHECK(Error(cx, "\r\n[}", 2, 2));
  CHECK(Error(cx, "{\"a\":[2,3],\r\n\"b\":,5,6}", 2, 5));

  CHECK(Error(cx, "\n\"bad string\n\"", 2, 12));
  CHECK(Error(cx, "\r\"bad string\r\"", 2, 12));
  CHECK(Error(cx, "\r\n\"bad string\r\n\"", 2, 12));

  CHECK(Error(cx, "{\n\"a\":[2,3],\r\"b\":,5,6}", 3, 5));
  CHECK(Error(cx, "{\r\"a\":[2,3],\n\"b\":,5,6}", 3, 5));
  CHECK(Error(cx, "[\"\\t\\q", 1, 6));
  CHECK(Error(cx, "[\"\\t\x00", 1, 5));
  CHECK(Error(cx, "[\"\\t\x01", 1, 5));
  CHECK(Error(cx, "[\"\\t\\\x00", 1, 6));
  CHECK(Error(cx, "[\"\\t\\\x01", 1, 6));

  // Unicode escape errors are messy.  The first bad character could be
  // non-hexadecimal, or it could be absent entirely.  Include tests where
  // there's a bad character, followed by zero to as many characters as are
  // needed to form a complete Unicode escape sequence, plus one.  (The extra
  // characters beyond are valuable because our implementation checks for
  // too-few subsequent characters first, before checking for subsequent
  // non-hexadecimal characters.  So \u<END>, \u0<END>, \u00<END>, and
  // \u000<END> are all *detected* as invalid by the same code path, but the
  // process of computing the first invalid character follows a different
  // code path for each.  And \uQQQQ, \u0QQQ, \u00QQ, and \u000Q are detected
  // as invalid by the same code path [ignoring which precise subexpression
  // triggers failure of a single condition], but the computation of the
  // first invalid character follows a different code path for each.)
  CHECK(Error(cx, "[\"\\t\\u", 1, 7));
  CHECK(Error(cx, "[\"\\t\\uZ", 1, 7));
  CHECK(Error(cx, "[\"\\t\\uZZ", 1, 7));
  CHECK(Error(cx, "[\"\\t\\uZZZ", 1, 7));
  CHECK(Error(cx, "[\"\\t\\uZZZZ", 1, 7));
  CHECK(Error(cx, "[\"\\t\\uZZZZZ", 1, 7));

  CHECK(Error(cx, "[\"\\t\\u0", 1, 8));
  CHECK(Error(cx, "[\"\\t\\u0Z", 1, 8));
  CHECK(Error(cx, "[\"\\t\\u0ZZ", 1, 8));
  CHECK(Error(cx, "[\"\\t\\u0ZZZ", 1, 8));
  CHECK(Error(cx, "[\"\\t\\u0ZZZZ", 1, 8));

  CHECK(Error(cx, "[\"\\t\\u00", 1, 9));
  CHECK(Error(cx, "[\"\\t\\u00Z", 1, 9));
  CHECK(Error(cx, "[\"\\t\\u00ZZ", 1, 9));
  CHECK(Error(cx, "[\"\\t\\u00ZZZ", 1, 9));

  CHECK(Error(cx, "[\"\\t\\u000", 1, 10));
  CHECK(Error(cx, "[\"\\t\\u000Z", 1, 10));
  CHECK(Error(cx, "[\"\\t\\u000ZZ", 1, 10));

  return true;
}

template <size_t N>
inline bool Error(JSContext* cx, const char (&input)[N], uint32_t expectedLine,
                  uint32_t expectedColumn) {
  AutoInflatedString str(cx);
  RootedValue dummy(cx);
  str = input;

  bool ok = JS_ParseJSON(cx, str.chars(), str.length(), &dummy);
  CHECK(!ok);

  JS::ExceptionStack exnStack(cx);
  CHECK(StealPendingExceptionStack(cx, &exnStack));

  JS::ErrorReportBuilder report(cx);
  CHECK(report.init(cx, exnStack, JS::ErrorReportBuilder::WithSideEffects));
  CHECK(report.report()->errorNumber == JSMSG_JSON_BAD_PARSE);

  UniqueChars lineAndColumnASCII =
      JS_smprintf("line %d column %d", expectedLine, expectedColumn);
  CHECK(strstr(report.toStringResult().c_str(), lineAndColumnASCII.get()) !=
        nullptr);

  /* We do not execute JS, so there should be no exception thrown. */
  CHECK(!JS_IsExceptionPending(cx));

  return true;
}
END_TEST(testParseJSON_error)

static bool Censor(JSContext* cx, unsigned argc, JS::Value* vp) {
  JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
  const unsigned expectedArgCount =
      JS::Prefs::experimental_json_parse_with_source() ? 3 : 2;
  MOZ_RELEASE_ASSERT(args.length() == expectedArgCount);
  MOZ_RELEASE_ASSERT(args[0].isString());
  args.rval().setNull();
  return true;
}

BEGIN_TEST(testParseJSON_reviver) {
  JSFunction* fun = JS_NewFunction(cx, Censor, 0, 0, "censor");
  CHECK(fun);

  JS::RootedValue filter(cx, JS::ObjectValue(*JS_GetFunctionObject(fun)));

  CHECK(TryParse(cx, "true", filter));
  CHECK(TryParse(cx, "false", filter));
  CHECK(TryParse(cx, "null", filter));
  CHECK(TryParse(cx, "1", filter));
  CHECK(TryParse(cx, "1.75", filter));
  CHECK(TryParse(cx, "[]", filter));
  CHECK(TryParse(cx, "[1]", filter));
  CHECK(TryParse(cx, "{}", filter));
  return true;
}

template <size_t N>
inline bool TryParse(JSContext* cx, const char (&input)[N],
                     JS::HandleValue filter) {
  AutoInflatedString str(cx);
  JS::RootedValue v(cx);
  str = input;
  CHECK(JS_ParseJSONWithReviver(cx, str.chars(), str.length(), filter, &v));
  CHECK(v.isNull());
  return true;
}
END_TEST(testParseJSON_reviver)

100%


¤ Dauer der Verarbeitung: 0.17 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung ist noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge