diff --git a/src/ScriptEngine.HostedScript/Library/Json/GlobalJsonFunctions.cs b/src/ScriptEngine.HostedScript/Library/Json/GlobalJsonFunctions.cs index f19eb2010..b9f2badf8 100644 --- a/src/ScriptEngine.HostedScript/Library/Json/GlobalJsonFunctions.cs +++ b/src/ScriptEngine.HostedScript/Library/Json/GlobalJsonFunctions.cs @@ -9,6 +9,7 @@ This Source Code Form is subject to the terms of the using ScriptEngine.Machine.Contexts; using Newtonsoft.Json; using System; +using System.Collections.Generic; namespace ScriptEngine.HostedScript.Library.Json { @@ -55,132 +56,140 @@ public static IAttachableContext CreateInstance() [ContextMethod("ПрочитатьJSON", "ReadJSON")] public IValue ReadJSON(JSONReader Reader, bool ReadToMap = false, IValue PropertiesWithDateValuesNames = null, IValue ExpectedDateFormat = null, string ReviverFunctionName = null, IValue ReviverFunctionModule = null, IValue ReviverFunctionAdditionalParameters = null, IValue RetriverPropertiesNames = null, int MaximumNesting = 500) { - if (ReadToMap) - return ReadJSONInMap(Reader); - else - return ReadJSONInStruct(Reader); + var jsonReader = new JsonReaderInternal(Reader); + return ReadToMap ? jsonReader.Read() : jsonReader.Read(); } - public IValue ReadJSONInStruct(JSONReader Reader, bool nestedArray = false) + internal class JsonReaderInternal { - if (nestedArray) - { - ArrayImpl NestedArray = new ArrayImpl(); + private readonly JSONReader _reader; + private Func _builder; + private Action _inserter; - while (Reader.Read()) + private void Init() + { + if (typeof(TStructure) == typeof(StructureImpl)) { - if (Reader.CurrentJsonTokenType == JsonToken.EndArray) - { - break; - } - else if (Reader.CurrentJsonTokenType == JsonToken.StartObject) - { - NestedArray.Add(ReadJSONInStruct(Reader)); - } - else if (Reader.CurrentJsonTokenType == JsonToken.StartArray) - { - NestedArray.Add(ReadJSONInStruct(Reader, true)); - } - else - NestedArray.Add(Reader.CurrentValue); + _builder = () => new StructureImpl(); + _inserter = (o, s, v) => ((StructureImpl)o).Insert(s, v); + } + else if (typeof(TStructure) == typeof(MapImpl)) + { + _builder = () => new MapImpl(); + _inserter = (o, s, v) =>((MapImpl)o).Insert(ValueFactory.Create(s), v); } - return NestedArray; + else + { + throw new InvalidOperationException(); + } + } + + public JsonReaderInternal(JSONReader reader) + { + _reader = reader; } - StructureImpl ResStruct = new StructureImpl(); + private IValue Create() => _builder(); - while ((Reader).Read()) + private void AddProperty(IValue obj, string str, IValue val) => _inserter(obj, str, val); + + public IValue Read() where T: IEnumerable { - if (Reader.CurrentJsonTokenType == JsonToken.PropertyName) + System.Diagnostics.Debug.Assert(typeof(T)==typeof(StructureImpl)||typeof(T)==typeof(MapImpl)); + Init(); + + try { - string PropertyName = Reader.CurrentValue.AsString(); - Reader.Read(); - - if (Reader.CurrentJsonTokenType == JsonToken.StartObject) - { - ResStruct.Insert(PropertyName, ReadJSONInStruct(Reader)); - } - else if (Reader.CurrentJsonTokenType == JsonToken.StartArray) - { - ResStruct.Insert(PropertyName, ReadJSONInStruct(Reader, true)); - } - else - { - ResStruct.Insert(PropertyName, Reader.CurrentValue); - } + if (ReadJsonValue(out var value)) + return value; } - else if (Reader.CurrentJsonTokenType == JsonToken.EndObject) + catch (JSONReaderException) { - break; + throw; } - else if (Reader.CurrentJsonTokenType == JsonToken.StartArray) + catch (Exception exc) { - return ReadJSONInStruct(Reader, true); + throw InvalidJsonException(exc.Message); } - } - return ResStruct; - } - public IValue ReadJSONInMap(JSONReader Reader, bool nestedArray = false) - { + throw InvalidJsonException(); + } - if (nestedArray) + private JsonToken ReadJsonToken() { - ArrayImpl NestedArray = new ArrayImpl(); + while (_reader.Read()) + { + var tok = _reader.CurrentJsonTokenType; + if (tok != JsonToken.Comment) + return tok; + } - while (Reader.Read()) + return JsonToken.None; + } + + private bool ReadJsonValue(out IValue value) + { + switch (ReadJsonToken()) { - if (Reader.CurrentJsonTokenType == JsonToken.EndArray) - { + case JsonToken.StartObject: + var jsonObject = Create(); + + while (ReadJsonToken() == JsonToken.PropertyName) + { + var propertyName = _reader.CurrentValue.AsString(); + if (!ReadJsonValue(out value)) + return false; + + AddProperty(jsonObject, propertyName, value); + } + + if (_reader.CurrentJsonTokenType == JsonToken.EndObject) + { + value = jsonObject; + return true; + } + break; + + case JsonToken.StartArray: + var resArray = new ArrayImpl(); + + while (ReadJsonValue(out value)) + { + resArray.Add(value); + } + + if (_reader.CurrentJsonTokenType == JsonToken.EndArray) + { + value = resArray; + return true; + } break; - } - else if (Reader.CurrentJsonTokenType == JsonToken.StartObject) - { - NestedArray.Add(ReadJSONInMap(Reader)); - } - else if (Reader.CurrentJsonTokenType == JsonToken.StartArray) - { - NestedArray.Add(ReadJSONInMap(Reader, true)); - } - else - NestedArray.Add(Reader.CurrentValue); + + case JsonToken.EndArray: + case JsonToken.EndObject: + case JsonToken.None: + break; + + default: + value = _reader.CurrentValue; + return true; } - return NestedArray; + + value = null; + return false; } - MapImpl ResStruct = new MapImpl(); - while ((Reader).Read()) + private RuntimeException InvalidJsonException(string message=null) { - if (Reader.CurrentJsonTokenType == JsonToken.PropertyName) - { - string PropertyName = Reader.CurrentValue.AsString(); - Reader.Read(); - - if (Reader.CurrentJsonTokenType == JsonToken.StartObject) - { - ResStruct.Insert(ValueFactory.Create(PropertyName), ReadJSONInMap(Reader)); - } - else if (Reader.CurrentJsonTokenType == JsonToken.StartArray) - { - ResStruct.Insert(ValueFactory.Create(PropertyName), ReadJSONInMap(Reader, true)); - } - else - { - ResStruct.Insert(ValueFactory.Create(PropertyName), Reader.CurrentValue); - } - } - else if (Reader.CurrentJsonTokenType == JsonToken.EndObject) - { - break; - } - else if (Reader.CurrentJsonTokenType == JsonToken.StartArray) - { - return ReadJSONInMap(Reader, true); - } + var addition = string.IsNullOrWhiteSpace(message) ? string.Empty : $"\n({message})"; + return new RuntimeException(string.Format(Locale.NStr + ("ru='Недопустимое состояние потока чтения JSON в строке {0} позиции {1}{2}'" + + "en='Invalid JSON reader state at line {0} position {1}{2}'"), + _reader.CurrentLine, _reader.CurrentPosition, addition)); } - return ResStruct; } + /// /// /// Выполняет преобразование строки, прочитанной в JSON-формате, в значение типа Дата. @@ -197,7 +206,7 @@ public IValue ReadJSONInMap(JSONReader Reader, bool nestedArray = false) [ContextMethod("ПрочитатьДатуJSON", "ReadJSONDate")] public IValue ReadJSONDate(string String, IValue Format) { - + var format = Format.GetRawValue() as SelfAwareEnumValue; var JSONDateFormatEnum = GlobalsManager.GetEnum(); DateFormatHandling dateFormatHandling = new DateFormatHandling(); @@ -209,14 +218,22 @@ public IValue ReadJSONDate(string String, IValue Format) else throw new RuntimeException(Locale.NStr("ru='Формат даты JavaScript не поддерживается.'; en='JavaScript date format is not supported'")); - string json = @"{""Date"":""" + String + @"""}"; + string json = @"{""Date"":""" + String + @"""}"; var settings = new JsonSerializerSettings { DateFormatHandling = dateFormatHandling - }; - var result = JsonConvert.DeserializeObject(json, settings); - return ValueFactory.Create((DateTime)result.Date); + }; + + try + { + var result = JsonConvert.DeserializeObject(json, settings); + return ValueFactory.Create((DateTime)result.Date); + } + catch (JsonException) + { + throw new RuntimeException(Locale.NStr("ru='Представление даты имеет неверный формат.'; en='Invalid date presentation format'")); + } } /// diff --git a/src/ScriptEngine.HostedScript/Library/Json/JSONReader.cs b/src/ScriptEngine.HostedScript/Library/Json/JSONReader.cs index 1019ceb5a..fab7cd12e 100644 --- a/src/ScriptEngine.HostedScript/Library/Json/JSONReader.cs +++ b/src/ScriptEngine.HostedScript/Library/Json/JSONReader.cs @@ -12,6 +12,22 @@ This Source Code Form is subject to the terms of the namespace ScriptEngine.HostedScript.Library.Json { + internal class JsonReaderInternal: JsonTextReader // из библиотеки Newtonsoft + { + public JsonReaderInternal(TextReader reader) : base(reader) { } + + public override bool Read() + { + if (!base.Read()) + return false; + + if (TokenType != JsonToken.Undefined) + return true; + + throw JSONReaderException.UnexpectedSymbol(); + } + } + /// /// /// Предназначен для последовательного чтения JSON-данных из файла или строки. @@ -20,15 +36,17 @@ namespace ScriptEngine.HostedScript.Library.Json public class JSONReader : AutoContext { - private JsonTextReader _reader; // Объект из библиотеки Newtonsoft для работы с форматом JSON + private JsonReaderInternal _reader; /// /// /// Возвращает true если для объекта чтения json был задан текст для парсинга. /// - private bool IsOpen() + private bool IsOpen() => _reader != null; + + private void CheckIfOpen() { - return _reader != null; + if (_reader == null) throw JSONReaderException.NotOpen(); } public JSONReader() @@ -59,7 +77,6 @@ public IValue CurrentPosition else return ValueFactory.Create(); // Неопределено } - } @@ -81,7 +98,6 @@ public IValue CurrentLine else return ValueFactory.Create(); // Неопределено } - } @@ -111,35 +127,31 @@ public IValue CurrentValue { get { - if (IsOpen()) + CheckIfOpen(); + + switch (_reader.TokenType) { - switch (_reader.TokenType) - { - case JsonToken.String: - case JsonToken.Comment: - case JsonToken.PropertyName: - return ValueFactory.Create((string)_reader.Value); + case JsonToken.String: + case JsonToken.Comment: + case JsonToken.PropertyName: + return ValueFactory.Create((string)_reader.Value); - case JsonToken.Integer: - case JsonToken.Float: - return ValueFactory.Create(Convert.ToDecimal(_reader.Value)); + case JsonToken.Integer: + case JsonToken.Float: + return ValueFactory.Create(Convert.ToDecimal(_reader.Value)); - case JsonToken.Boolean: - return ValueFactory.Create((bool)_reader.Value); + case JsonToken.Boolean: + return ValueFactory.Create((bool)_reader.Value); - case JsonToken.Date: - return ValueFactory.Create((DateTime)_reader.Value); + case JsonToken.Date: + return ValueFactory.Create((DateTime)_reader.Value); - case JsonToken.Null: - case JsonToken.Undefined: - return ValueFactory.Create(); + case JsonToken.Null: + return ValueFactory.Create(); - default: - throw CannotGetValueException(); - } + default: + throw JSONReaderException.CannotGetValue();; } - else - throw NotOpenException(); } } @@ -153,12 +165,8 @@ public JsonToken CurrentJsonTokenType { get { - if (IsOpen()) - { - return _reader.TokenType; - } - else - throw NotOpenException(); + CheckIfOpen(); + return _reader.TokenType; } } @@ -174,52 +182,47 @@ public IValue CurrentValueType { get { - if (IsOpen()) - { - string JSONValueType = "None"; + CheckIfOpen(); - switch (_reader.TokenType) - { - case JsonToken.Null: - case JsonToken.Undefined: - JSONValueType = "Null"; - break; - case JsonToken.StartObject: - JSONValueType = "ObjectStart"; - break; - case JsonToken.StartArray: - JSONValueType = "ArrayStart"; - break; - case JsonToken.PropertyName: - JSONValueType = "PropertyName"; - break; - case JsonToken.Comment: - JSONValueType = "Comment"; - break; - case JsonToken.Integer: - case JsonToken.Float: - JSONValueType = "Number"; - break; - case JsonToken.String: - JSONValueType = "String"; - break; - case JsonToken.Boolean: - JSONValueType = "Boolean"; - break; - case JsonToken.EndObject: - JSONValueType = "ObjectEnd"; - break; - case JsonToken.EndArray: - JSONValueType = "ArrayEnd"; - break; - } - return GlobalsManager.GetEnum()[JSONValueType]; + string JSONValueType = "None"; + switch (_reader.TokenType) + { + case JsonToken.Null: + JSONValueType = "Null"; + break; + case JsonToken.StartObject: + JSONValueType = "ObjectStart"; + break; + case JsonToken.StartArray: + JSONValueType = "ArrayStart"; + break; + case JsonToken.PropertyName: + JSONValueType = "PropertyName"; + break; + case JsonToken.Comment: + JSONValueType = "Comment"; + break; + case JsonToken.Integer: + case JsonToken.Float: + JSONValueType = "Number"; + break; + case JsonToken.String: + JSONValueType = "String"; + break; + case JsonToken.Boolean: + JSONValueType = "Boolean"; + break; + case JsonToken.EndObject: + JSONValueType = "ObjectEnd"; + break; + case JsonToken.EndArray: + JSONValueType = "ArrayEnd"; + break; } - else - throw NotOpenException(); - } + return GlobalsManager.GetEnum()[JSONValueType]; + } } /// @@ -227,12 +230,9 @@ public IValue CurrentValueType /// Завершает чтение текста JSON из файла или строки. /// /// - /// - /// [ContextMethod("Закрыть", "Close")] public void Close() { - if (_reader != null) { _reader.Close(); @@ -253,7 +253,6 @@ public void Close() [ContextMethod("ОткрытьФайл", "OpenFile")] public void OpenFile(string JSONFileName, IValue encoding = null) { - if (IsOpen()) Close(); @@ -271,8 +270,10 @@ public void OpenFile(string JSONFileName, IValue encoding = null) throw new RuntimeException(e.Message, e); } - _reader = new JsonTextReader(_fileReader); - + _reader = new JsonReaderInternal(_fileReader) + { + SupportMultipleContent = true + }; } @@ -284,32 +285,26 @@ public void OpenFile(string JSONFileName, IValue encoding = null) [ContextMethod("Пропустить", "Skip")] public bool Skip() { + CheckIfOpen(); - if (IsOpen()) + if (_reader.TokenType == JsonToken.StartArray || _reader.TokenType == JsonToken.StartObject) { - if (_reader.TokenType == JsonToken.StartArray || _reader.TokenType == JsonToken.StartObject) + while (_reader.Read()) { - while (_reader.Read()) + if (_reader.TokenType == JsonToken.EndArray || _reader.TokenType == JsonToken.EndObject) { - if (_reader.TokenType == JsonToken.EndArray || _reader.TokenType == JsonToken.EndObject) - { - return _reader.Read(); - } - } - return true; - } - else - { - if (_reader.Read()) return _reader.Read(); - else - return false; + } } - + return true; } else - throw NotOpenException(); - + { + if (_reader.Read()) + return _reader.Read(); + else + return false; + } } @@ -320,8 +315,8 @@ public bool Skip() [ContextMethod("Прочитать", "Read")] public bool Read() { + CheckIfOpen(); return _reader.Read(); - } @@ -340,20 +335,35 @@ public void SetString(string JSONString) if (IsOpen()) Close(); - _reader = new JsonTextReader(new StringReader(JSONString)); + _reader = new JsonReaderInternal(new StringReader(JSONString)) + { + SupportMultipleContent = true + }; } + } - RuntimeException NotOpenException() + public class JSONReaderException : RuntimeException + { + public JSONReaderException(string message) : base(message) + { + } + + public static JSONReaderException NotOpen() { - return new RuntimeException(Locale.NStr + return new JSONReaderException(Locale.NStr ("ru='Источник данных JSON не открыт'; en='JSON data source is not opened'")); } - RuntimeException CannotGetValueException() + public static JSONReaderException CannotGetValue() { - return new RuntimeException(Locale.NStr + return new JSONReaderException(Locale.NStr ("ru='Текущее значение JSON не может быть получено';en='Cannot get current JSON value'")); } + public static JSONReaderException UnexpectedSymbol() + { + return new JSONReaderException(Locale.NStr + ("ru='Непредвиденный символ при чтении JSON';en='Unexpected symbol during JSON reading'")); + } } } diff --git a/tests/global-json.os b/tests/global-json.os new file mode 100644 index 000000000..506df914e --- /dev/null +++ b/tests/global-json.os @@ -0,0 +1,362 @@ +Перем юТест; + +Функция ПолучитьСписокТестов(Тестирование) Экспорт + + юТест = Тестирование; + + СписокТестов = Новый Массив; + + СписокТестов.Добавить("Тест_ДолженПроверить_ПолучениеМассива"); + СписокТестов.Добавить("Тест_ДолженПроверить_ПолучениеСтруктуры"); + СписокТестов.Добавить("Тест_ДолженПроверить_ПолучениеСоответствия"); + СписокТестов.Добавить("Тест_ДолженПроверить_ПолучениеЧисла"); + СписокТестов.Добавить("Тест_ДолженПроверить_ПолучениеСтроки"); + СписокТестов.Добавить("Тест_ДолженПроверить_ПолучениеПустогоМассива"); + СписокТестов.Добавить("Тест_ДолженПроверить_ПолучениеПустойСтруктуры"); + СписокТестов.Добавить("Тест_ДолженПроверить_ПолучениеПустогоСоответствия"); + СписокТестов.Добавить("Тест_ДолженПроверить_ПолучениеВложенныхМассивов"); + + // issue #1373 + СписокТестов.Добавить("Тест_ДолженПроверить_ОднострочныйКомментарийВКонцеМассива"); + СписокТестов.Добавить("Тест_ДолженПроверить_ОднострочныйКомментарийВнутриСтуктуры"); + СписокТестов.Добавить("Тест_ДолженПроверить_ОднострочныйКомментарийВНачалеМассива"); + СписокТестов.Добавить("Тест_ДолженПроверить_МногострочныйКомментарийВнутриСтуктуры"); + СписокТестов.Добавить("Тест_ДолженПроверить_МногострочныйКомментарийВнутриМассива"); + + СписокТестов.Добавить("Тест_ДолженПроверить_ПродолжениеЧтения"); + СписокТестов.Добавить("Тест_ДолженПроверить_ПродолжениеЧтенияСИзменениемСтруктуры"); + + СписокТестов.Добавить("Тест_ДолженВызватьОшибку_ДляUndefined"); + СписокТестов.Добавить("Тест_ДолженВызватьОшибку_ПриНезакрытомМассиве"); + СписокТестов.Добавить("Тест_ДолженВызватьОшибку_ПриНезакрытомОбъекте"); + СписокТестов.Добавить("Тест_ДолженВызватьОшибку_ПриНезакрытомВложенномМассиве"); + СписокТестов.Добавить("Тест_ДолженВызватьОшибку_ПриНезакрытомВложенномОбъекте"); + СписокТестов.Добавить("Тест_ДолженВызватьОшибку_ПриПропущенномЗначенииСвойства"); + СписокТестов.Добавить("Тест_ДолженВызватьОшибку_ПриНезакрытомКомментарии"); + СписокТестов.Добавить("Тест_ДолженВызватьОшибку_ПриНедопустимомКлючеСтруктуры"); + СписокТестов.Добавить("Тест_ДолженПроверить_ПроизвольныйКлючСоответствия"); + СписокТестов.Добавить("Тест_ДолженВызватьОшибку_ПриПустомЗначенииВнутриМассива"); + СписокТестов.Добавить("Тест_ДолженВызватьОшибку_ПриПустомЗначенииВКонцеМассива"); + СписокТестов.Добавить("Тест_ДолженВызватьОшибку_ПриПустомЗначенииСвойства"); + СписокТестов.Добавить("Тест_ДолженПроверить_ЗапятуюВКонцеМассива"); + СписокТестов.Добавить("Тест_ДолженПроверить_ЗапятуюВКонцеОбъекта"); + + Возврат СписокТестов; + +КонецФункции + +Функция ПрочитатьJSONИзСтроки(Стр, Знач ВСоответствие=Ложь) + Чтение = Новый ЧтениеJSON(); + Чтение.УстановитьСтроку(Стр); + Результат = ПрочитатьJSON(Чтение, ВСоответствие); + Чтение.Закрыть(); + Возврат Результат; +КонецФункции + +Процедура Тест_ДолженПроверить_ПолучениеМассива() Экспорт + Текст = "[123,456,789]"; + Результат = ПрочитатьJSONИзСтроки(Текст); + + юТест.ПроверитьРавенство(Тип("Массив"), ТипЗнч(Результат)); + юТест.ПроверитьРавенство(3, Результат.Количество()); + юТест.ПроверитьРавенство(456, Результат[1]); +КонецПроцедуры + +Процедура Тест_ДолженПроверить_ПолучениеСтруктуры() Экспорт + Текст = "{""Поле1"":123,""Поле2"":456}"; + Результат = ПрочитатьJSONИзСтроки(Текст); + + юТест.ПроверитьРавенство(Тип("Структура"), ТипЗнч(Результат) ); + юТест.ПроверитьРавенство(2, Результат.Количество()); + юТест.ПроверитьРавенство(456, Результат.Поле2); +КонецПроцедуры + +Процедура Тест_ДолженПроверить_ПолучениеСоответствия() Экспорт + Текст = "{""Поле1"":123,""Поле2"":456}"; + Результат = ПрочитатьJSONИзСтроки(Текст,Истина); + + юТест.ПроверитьРавенство(Тип("Соответствие"), ТипЗнч(Результат)); + юТест.ПроверитьРавенство(2, Результат.Количество()); + юТест.ПроверитьРавенство(456, Результат["Поле2"]); +КонецПроцедуры + +Процедура Тест_ДолженПроверить_ПолучениеЧисла() Экспорт + Текст = "321"; + Результат = ПрочитатьJSONИзСтроки(Текст); + + юТест.ПроверитьРавенство(Тип("Число"), ТипЗнч(Результат)); + юТест.ПроверитьРавенство(321, Результат); +КонецПроцедуры + +Процедура Тест_ДолженПроверить_ПолучениеСтроки() Экспорт + Текст = """абв"""; + Результат = ПрочитатьJSONИзСтроки(Текст); + + юТест.ПроверитьРавенство(ТипЗнч(Результат), Тип("Строка")); + юТест.ПроверитьРавенство(Результат, "абв"); +КонецПроцедуры + +Процедура Тест_ДолженПроверить_ПолучениеПустогоМассива() Экспорт + Текст = "[]"; + Результат = ПрочитатьJSONИзСтроки(Текст); + + юТест.ПроверитьРавенство(Тип("Массив"), ТипЗнч(Результат) ); + юТест.ПроверитьРавенство(0, Результат.Количество()); +КонецПроцедуры + +Процедура Тест_ДолженПроверить_ПолучениеПустойСтруктуры() Экспорт + Текст = "{}"; + Результат = ПрочитатьJSONИзСтроки(Текст); + + юТест.ПроверитьРавенство(Тип("Структура"), ТипЗнч(Результат)); + юТест.ПроверитьРавенство(Результат.Количество(), 0); +КонецПроцедуры + +Процедура Тест_ДолженПроверить_ПолучениеПустогоСоответствия() Экспорт + Текст = "{}"; + Результат = ПрочитатьJSONИзСтроки(Текст,Истина); + + юТест.ПроверитьРавенство(Тип("Соответствие"), ТипЗнч(Результат)); + юТест.ПроверитьРавенство(Результат.Количество(), 0); +КонецПроцедуры + +Процедура Тест_ДолженПроверить_ПолучениеВложенныхМассивов() Экспорт + Текст = "[[123,456],789,[-3,-2,""-0""],{""Ф"":[""Ы"",222]}]"; + Результат = ПрочитатьJSONИзСтроки(Текст); + + юТест.ПроверитьРавенство(Тип("Массив"), ТипЗнч(Результат)); + юТест.ПроверитьРавенство(4, Результат.Количество()); + юТест.ПроверитьРавенство(Тип("Число"), ТипЗнч(Результат[1])); + юТест.ПроверитьРавенство(789, Результат[1]); + юТест.ПроверитьРавенство(Тип("Массив"), ТипЗнч(Результат[2])); + юТест.ПроверитьРавенство(3, Результат[2].Количество()); + юТест.ПроверитьРавенство("-0", Результат[2][2]); + юТест.ПроверитьРавенство(Тип("Структура"), ТипЗнч(Результат[3])); +КонецПроцедуры + +Процедура Тест_ДолженПроверить_ОднострочныйКомментарийВКонцеМассива() Экспорт + Текст = "[ + |{ + | ""NAME"": ""n1"", + | ""Method"": ""m1"", + | ""PATH"": ""p1"" + |}, + |{ + | ""NAME"": ""n2"", + | //""Method"": ""m2"", + | ""PATH"": ""p2"" + |} + |//}, + |//{ + |// ""NAME"": """", + |]"; + Результат = ПрочитатьJSONИзСтроки(Текст); + + юТест.ПроверитьРавенство(2, Результат.Количество()); + юТест.ПроверитьРавенство("p2", Результат[1].PATH); +КонецПроцедуры + +Процедура Тест_ДолженПроверить_ОднострочныйКомментарийВнутриСтуктуры() Экспорт + Текст = " + |{ + | ""test"": //fail + | ""pass"" + |}"; + Результат = ПрочитатьJSONИзСтроки(Текст); + + юТест.ПроверитьРавенство("pass", Результат.test); +КонецПроцедуры + +Процедура Тест_ДолженПроверить_ОднострочныйКомментарийВНачалеМассива() Экспорт + Текст = " + |[// !!! + |""fail"",""pass""] + |"; + Результат = ПрочитатьJSONИзСтроки(Текст); + + юТест.ПроверитьРавенство("pass", Результат[1]); +КонецПроцедуры + +Процедура Тест_ДолженПроверить_МногострочныйКомментарийВнутриСтуктуры() Экспорт + Текст = " + |{ + | ""test"": /*fail + | ""??""*/ ""ok"" + |}"; + Результат = ПрочитатьJSONИзСтроки(Текст); + + юТест.ПроверитьРавенство("ok", Результат.test); +КонецПроцедуры + +Процедура Тест_ДолженПроверить_МногострочныйКомментарийВнутриМассива() Экспорт + Текст = " + |[ + | ""test"", /*fail + | ""??""]*/ ""ok"" + |]"; + Результат = ПрочитатьJSONИзСтроки(Текст); + + юТест.ПроверитьРавенство("ok", Результат[1]); +КонецПроцедуры + +Процедура Тест_ДолженПроверить_ПродолжениеЧтения() Экспорт + Текст = "[123,456] {""аб"":""вг"",""де"":""жз"",""ик"":""лм""}"; + Чтение = Новый ЧтениеJSON(); + Чтение.УстановитьСтроку(Текст); + Результат1 = ПрочитатьJSON(Чтение); + Результат2 = ПрочитатьJSON(Чтение); + Чтение.Закрыть(); + + юТест.ПроверитьРавенство(Тип("Массив"), ТипЗнч(Результат1)); + юТест.ПроверитьРавенство(2, Результат1.Количество()); + юТест.ПроверитьРавенство(Тип("Структура"), ТипЗнч(Результат2)); + юТест.ПроверитьРавенство(3, Результат2.Количество()); +КонецПроцедуры + +Процедура Тест_ДолженПроверить_ПродолжениеЧтенияСИзменениемСтруктуры() Экспорт + Текст = "{""аб"":""вг"",""де"":""жз""} {""ик"":""лм""}"; + Чтение = Новый ЧтениеJSON(); + Чтение.УстановитьСтроку(Текст); + Результат1 = ПрочитатьJSON(Чтение); + Результат2 = ПрочитатьJSON(Чтение,Истина); + Чтение.Закрыть(); + + юТест.ПроверитьРавенство(Тип("Структура"), ТипЗнч(Результат1)); + юТест.ПроверитьРавенство(2, Результат1.Количество()); + юТест.ПроверитьРавенство(Тип("Соответствие"), ТипЗнч(Результат2)); + юТест.ПроверитьРавенство(1, Результат2.Количество()); + юТест.ПроверитьРавенство("лм", Результат2["ик"]); +КонецПроцедуры + + +Процедура Тест_ДолженВызватьОшибку_ДляUndefined() Экспорт + Текст = "[123,undefined,456]"; + Попытка + Результат = ПрочитатьJSONИзСтроки(Текст); + Исключение + Возврат; + КонецПопытки; + ВызватьИсключение "Должно было быть выдано исключение, но его не было"; +КонецПроцедуры + +Процедура Тест_ДолженВызватьОшибку_ПриНезакрытомМассиве() Экспорт + Текст = "[[[123,456]]"; + Попытка + Результат = ПрочитатьJSONИзСтроки(Текст); + Исключение + Возврат; + КонецПопытки; + ВызватьИсключение "Должно было быть выдано исключение, но его не было"; +КонецПроцедуры + +Процедура Тест_ДолженВызватьОшибку_ПриНезакрытомОбъекте() Экспорт + Текст = "{""aбв"":456"; + Попытка + Результат = ПрочитатьJSONИзСтроки(Текст); + Исключение + Возврат; + КонецПопытки; + ВызватьИсключение "Должно было быть выдано исключение, но его не было"; +КонецПроцедуры + +Процедура Тест_ДолженВызватьОшибку_ПриНезакрытомВложенномМассиве() Экспорт + Текст = "{""aбв"":[456,789}"; + Попытка + Результат = ПрочитатьJSONИзСтроки(Текст); + Исключение + Возврат; + КонецПопытки; + ВызватьИсключение "Должно было быть выдано исключение, но его не было"; +КонецПроцедуры + +Процедура Тест_ДолженВызватьОшибку_ПриНезакрытомВложенномОбъекте() Экспорт + Текст = "[{""aбв"":456]"; + Попытка + Результат = ПрочитатьJSONИзСтроки(Текст); + Исключение + Возврат; + КонецПопытки; + ВызватьИсключение "Должно было быть выдано исключение, но его не было"; +КонецПроцедуры + +Процедура Тест_ДолженВызватьОшибку_ПриПропущенномЗначенииСвойства() Экспорт + Текст = "{""aбв"":}"; + Попытка + Результат = ПрочитатьJSONИзСтроки(Текст); + Исключение + Возврат; + КонецПопытки; + ВызватьИсключение "Должно было быть выдано исключение, но его не было"; +КонецПроцедуры + +Процедура Тест_ДолженВызватьОшибку_ПриНезакрытомКомментарии() Экспорт + Текст = "[123,456 /*]"; + Попытка + Результат = ПрочитатьJSONИзСтроки(Текст); + Исключение + Возврат; + КонецПопытки; + ВызватьИсключение "Должно было быть выдано исключение, но его не было"; +КонецПроцедуры + +Процедура Тест_ДолженВызватьОшибку_ПриНедопустимомКлючеСтруктуры() Экспорт + Текст = "{""123"":""456""}"; + Попытка + Результат = ПрочитатьJSONИзСтроки(Текст); + Исключение + Возврат; + КонецПопытки; + ВызватьИсключение "Должно было быть выдано исключение, но его не было"; +КонецПроцедуры + +Процедура Тест_ДолженПроверить_ПроизвольныйКлючСоответствия() Экспорт + Текст = "{""%/$!"":""456""}"; + Результат = ПрочитатьJSONИзСтроки(Текст, Истина); + юТест.ПроверитьРавенство("456", Результат["%/$!"]); +КонецПроцедуры + +Процедура Тест_ДолженВызватьОшибку_ПриПустомЗначенииВнутриМассива() Экспорт + Текст = "[123,,456]"; + Попытка + Результат = ПрочитатьJSONИзСтроки(Текст); + Исключение + Возврат; + КонецПопытки; + ВызватьИсключение "Должно было быть выдано исключение, но его не было"; +КонецПроцедуры + +Процедура Тест_ДолженВызватьОшибку_ПриПустомЗначенииВКонцеМассива() Экспорт + Текст = "[123,456,,]"; + Попытка + Результат = ПрочитатьJSONИзСтроки(Текст); + Исключение + Возврат; + КонецПопытки; + ВызватьИсключение "Должно было быть выдано исключение, но его не было"; +КонецПроцедуры + +Процедура Тест_ДолженВызватьОшибку_ПриПустомЗначенииСвойства() Экспорт + Текст = "{""аб"": , ""еж"":""кл""}";; + Попытка + Результат = ПрочитатьJSONИзСтроки(Текст); + Исключение + Возврат; + КонецПопытки; + ВызватьИсключение "Должно было быть выдано исключение, но его не было"; +КонецПроцедуры + +Процедура Тест_ДолженПроверить_ЗапятуюВКонцеМассива() Экспорт + Текст = "[123,456,789,]"; + Результат = ПрочитатьJSONИзСтроки(Текст); + + юТест.ПроверитьРавенство(3, Результат.Количество()); + юТест.ПроверитьРавенство(789, Результат[2]); +КонецПроцедуры + +Процедура Тест_ДолженПроверить_ЗапятуюВКонцеОбъекта() Экспорт + Текст = "{""аб"":""гд"",""еж"":""кл"",}"; + Результат = ПрочитатьJSONИзСтроки(Текст); + + юТест.ПроверитьРавенство(2, Результат.Количество()); + юТест.ПроверитьРавенство("кл", Результат["еж"]); +КонецПроцедуры diff --git a/tests/json/json-mock.json b/tests/json/json-mock.json index 519215a78..c570d1e8e 100644 --- a/tests/json/json-mock.json +++ b/tests/json/json-mock.json @@ -1,6 +1,5 @@ { "Null": null, - "Неопределено": undefined, "Ложь": false, "Истина": true, "Число (плавающая точка)": 1.001e-2, @@ -17,7 +16,6 @@ "Пустой объект": {}, "Массив": [ null, - undefined, false, true, 1.001e-2, diff --git a/tests/json/test-json_reader.os b/tests/json/test-json_reader.os index 1d1487290..75a867d59 100644 --- a/tests/json/test-json_reader.os +++ b/tests/json/test-json_reader.os @@ -16,6 +16,8 @@ СписокТестов.Добавить("Тест_Должен_СверитьХешСуммуРезультатаПарсингаJSON"); СписокТестов.Добавить("Тест_Должен_СверитьХешСуммуРезультатаПарсингаJSONВСтруктуру"); СписокТестов.Добавить("Тест_Должен_СверитьХешСуммуРезультатаПарсингаJSONМассива"); + + СписокТестов.Добавить("Тест_ДолженВызватьОшибку_ДляUndefined"); Возврат СписокТестов; КонецФункции @@ -57,7 +59,7 @@ СтруктураДанных = ПолучитьСтруктуруДанных("json/json-mock.json", Истина); - юТест.ПроверитьРавенство(РассчитатьХешСумму(СтруктураДанных), 4099998885); + юТест.ПроверитьРавенство(РассчитатьХешСумму(СтруктураДанных), 960829385); КонецПроцедуры @@ -129,4 +131,16 @@ Возврат Результат; -КонецФункции \ No newline at end of file +КонецФункции + +Процедура Тест_ДолженВызватьОшибку_ДляUndefined() Экспорт + Текст = "undefined"; + Чтение = Новый ЧтениеJSON; + Чтение.УстановитьСтроку(Текст); + Попытка + Результат = Чтение.Прочитать(); + Исключение + Возврат; + КонецПопытки; + ВызватьИсключение "Должно было быть выдано исключение, но его не было"; +КонецПроцедуры