diff --git a/src/OneScript.StandardLibrary/TypeDescriptions/TypeComparer.cs b/src/OneScript.StandardLibrary/TypeDescriptions/TypeComparer.cs new file mode 100644 index 000000000..b48b568aa --- /dev/null +++ b/src/OneScript.StandardLibrary/TypeDescriptions/TypeComparer.cs @@ -0,0 +1,66 @@ +/*---------------------------------------------------------- +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/. +----------------------------------------------------------*/ +using System; +using System.Collections.Generic; +using OneScript.Types; +using OneScript.Values; + +namespace OneScript.StandardLibrary.TypeDescriptions +{ + internal class TypeComparer : IComparer + { + private const string TYPE_BINARYDATA_NAME = "ДвоичныеДанные"; + private static readonly IDictionary primitives = new Dictionary(); + + public int Compare(BslTypeValue x, BslTypeValue y) + { + if (x.TypeValue.Equals(y)) return 0; + + var primitiveX = PrimitiveIndex(x); + var primitiveY = PrimitiveIndex(y); + + if (primitiveX != -1) + { + if (primitiveY != -1) + return primitiveX - primitiveY; + + return -1; + } + + if (primitiveY != -1) + return 1; + + return x.TypeValue.Id.CompareTo(y.TypeValue.Id); + } + + private int PrimitiveIndex(BslTypeValue type) + { + if (StringComparer.CurrentCultureIgnoreCase.Equals(type.TypeValue.Name, TYPE_BINARYDATA_NAME)) + { + // Пора двоичным данным стать примитивом + return 1; + } + + if (primitives.TryGetValue(type.TypeValue, out var index)) + return index; + + return -1; + } + + static TypeComparer() + { + primitives.Add(BasicTypes.Boolean, 0); + primitives.Add(BasicTypes.String, 2); + primitives.Add(BasicTypes.Date, 3); + primitives.Add(BasicTypes.Null, 4); + primitives.Add(BasicTypes.Number, 5); + primitives.Add(BasicTypes.Type, 6); + } + + } +} + \ No newline at end of file diff --git a/src/OneScript.StandardLibrary/TypeDescriptions/TypeDescription.cs b/src/OneScript.StandardLibrary/TypeDescriptions/TypeDescription.cs index 8585c1d59..0f9c3b164 100644 --- a/src/OneScript.StandardLibrary/TypeDescriptions/TypeDescription.cs +++ b/src/OneScript.StandardLibrary/TypeDescriptions/TypeDescription.cs @@ -5,6 +5,7 @@ This Source Code Form is subject to the terms of the at http://mozilla.org/MPL/2.0/. ----------------------------------------------------------*/ +using System; using System.Collections.Generic; using System.Linq; using OneScript.Contexts; @@ -22,27 +23,34 @@ public class TypeDescription : AutoContext { private readonly List _types = new List(); - private const string TYPE_BINARYDATA_NAME = "ДвоичныеДанные"; + public TypeDescription(IEnumerable types = null) + { + if (types != null) + { + _types.AddRange(types); + } + + NumberQualifiers = new NumberQualifiers(); + StringQualifiers = new StringQualifiers(); + DateQualifiers = new DateQualifiers(); + BinaryDataQualifiers = new BinaryDataQualifiers(); + } - public TypeDescription(IEnumerable types = null, - NumberQualifiers numberQualifiers = null, - StringQualifiers stringQualifiers = null, - DateQualifiers dateQualifiers = null, - BinaryDataQualifiers binaryDataQualifiers = null) + internal TypeDescription(IEnumerable types, + NumberQualifiers numberQualifiers, + StringQualifiers stringQualifiers, + DateQualifiers dateQualifiers, + BinaryDataQualifiers binaryDataQualifiers) { if (types != null) { _types.AddRange(types); } - NumberQualifiers = numberQualifiers != null && _types.Contains(TypeNumber()) ? - numberQualifiers : new NumberQualifiers(); - StringQualifiers = stringQualifiers != null && _types.Contains(TypeString()) ? - stringQualifiers : new StringQualifiers(); - DateQualifiers = dateQualifiers != null && _types.Contains(TypeDate()) ? - dateQualifiers : new DateQualifiers(); - BinaryDataQualifiers = binaryDataQualifiers != null && _types.Any(x => x.TypeValue.Name == TYPE_BINARYDATA_NAME) ? - binaryDataQualifiers : new BinaryDataQualifiers(); + NumberQualifiers = numberQualifiers; + StringQualifiers = stringQualifiers; + DateQualifiers = dateQualifiers; + BinaryDataQualifiers = binaryDataQualifiers; } [ContextProperty("КвалификаторыЧисла", "NumberQualifiers")] @@ -70,16 +78,30 @@ public ArrayImpl Types() return result; } + internal IEnumerable TypesInternal() + { + return _types; + } + [ContextMethod("СодержитТип", "ContainsType")] public bool ContainsType(IValue type) { if (type is BslTypeValue typeVal) + { + if (typeVal.TypeValue.Equals(BasicTypes.Undefined)) + { + // тип "Неопределено" содержится в любом явно определенном составном типе + // и не содержится в типе Произвольный (когда явно не указан состав типов) + // или когда указан один конкретный тип + return (_types.Count > 1); + } return _types.Contains(typeVal); + } throw RuntimeException.InvalidArgumentType(nameof(type)); } - IValueAdjuster GetAdjusterForType(BslTypeValue type) + private IValueAdjuster GetAdjusterForType(BslTypeValue type) { var value = type.TypeValue; @@ -95,158 +117,63 @@ IValueAdjuster GetAdjusterForType(BslTypeValue type) if (value.Equals(BasicTypes.Boolean)) return new BooleanTypeAdjuster(); + if (value.Equals(BasicTypes.Undefined)) + return new UndefinedTypeAdjuster(); + return null; } [ContextMethod("ПривестиЗначение", "AdjustValue")] - public IValue AdjustValue(IValue value = null) + public IValue AdjustValue(IValue pValue = null) { - + var value = pValue?.GetRawValue(); if (_types.Count == 0) { return value ?? ValueFactory.Create(); } - BslTypeValue typeToCast = null; - - if (value != null && value.SystemType != BasicTypes.Undefined) + if (value != null) { var valueType = new BslTypeValue(value.SystemType); - if (_types.Contains(valueType)) + if (ContainsType(valueType)) { // Если такой тип у нас есть - typeToCast = valueType; + var adjuster = GetAdjusterForType(valueType); + var adjustedValue = adjuster?.Adjust(value) ?? value; + return adjustedValue; } } - if (typeToCast == null) - { - // Если типа нет, то нужно брать значение по-умолчанию - if (_types.Count != 1) - { - // много типов - Неопределено - return ValueFactory.Create(); - } - - typeToCast = _types[0]; - } - - var adjuster = GetAdjusterForType(typeToCast); - - return adjuster?.Adjust(value) ?? ValueFactory.Create(); - } - - private static IList ConstructTypeList(ITypeManager typeManager, IValue types) - { - var typesList = new List(); - if (types == null) - return typesList; - - types = types.GetRawValue(); - if (types.SystemType == BasicTypes.String) - { - var typeNames = types.AsString().Split(','); - foreach (var typeName in typeNames) - { - if (string.IsNullOrWhiteSpace(typeName)) - continue; - - var typeValue = new BslTypeValue(typeManager.GetTypeByName(typeName.Trim())); - if (!typesList.Contains(typeValue)) - typesList.Add(typeValue); - } - } else if (types is ArrayImpl arrayOfTypes) - { - foreach (var type in arrayOfTypes) - { - var rawType = type.GetRawValue() as BslTypeValue; - if (rawType == null) - continue; - - if (!typesList.Contains(rawType)) - typesList.Add(rawType); - } - } - else if (types.SystemType != BasicTypes.Undefined) + foreach (var type in _types) { - return null; // далее будет исключение + var adjuster = GetAdjusterForType(type); + var adjustedValue = adjuster?.Adjust(value); + if (adjustedValue != null) + return adjustedValue; } - // для Неопределено возвращается пустой список - return typesList; - } - - static BslTypeValue TypeNumber() - { - return new BslTypeValue(BasicTypes.Number); - } - - static BslTypeValue TypeBoolean() - { - return new BslTypeValue(BasicTypes.Boolean); - } - - static BslTypeValue TypeString() - { - return new BslTypeValue(BasicTypes.String); - } - - static BslTypeValue TypeDate() - { - return new BslTypeValue(BasicTypes.Date); + return ValueFactory.Create(); } public static TypeDescription StringType(int length = 0, - AllowedLengthEnum allowedLength = AllowedLengthEnum.Variable) + AllowedLengthEnum allowedLength = AllowedLengthEnum.Variable) { - var stringQualifier = new StringQualifiers(length, allowedLength); - return new TypeDescription(new BslTypeValue[] { TypeString() }, null, stringQualifier); + return TypeDescriptionBuilder.OfType(BasicTypes.String) + .SetStringQualifiers(new StringQualifiers(length, allowedLength)) + .Build(); } public static TypeDescription IntegerType(int length = 10, - AllowedSignEnum allowedSign = AllowedSignEnum.Any) + AllowedSignEnum allowedSign = AllowedSignEnum.Any) { - var numberQualifier = new NumberQualifiers(length, 0, allowedSign); - return new TypeDescription(new BslTypeValue[] { TypeNumber() }, numberQualifier); + return TypeDescriptionBuilder.OfType(BasicTypes.Number) + .SetNumberQualifiers(new NumberQualifiers(length, 0, allowedSign)) + .Build(); } public static TypeDescription BooleanType() { - return new TypeDescription(new BslTypeValue[] { TypeBoolean() }); - } - - - private class TypeQualifiersSet - { - public readonly NumberQualifiers numberQualifiers = null; - public readonly StringQualifiers stringQualifiers = null; - public readonly DateQualifiers dateQualifiers = null; - public readonly BinaryDataQualifiers binaryDataQualifiers = null; - - public TypeQualifiersSet(IValue p2, IValue p3, IValue p4, IValue p5, IValue p6, IValue p7) - { - int nParam = 1; - foreach (var qual in new[] { p2, p3, p4, p5, p6, p7 }) - { - nParam++; - - if (qual == null || qual.Equals(BslUndefinedValue.Instance)) - continue; - - switch (qual.GetRawValue()) - { - case NumberQualifiers nq: numberQualifiers = nq; break; - - case StringQualifiers sq: stringQualifiers = sq; break; - - case DateQualifiers dq: dateQualifiers = dq; break; - - case BinaryDataQualifiers bdq: binaryDataQualifiers = bdq; break; - - default: throw RuntimeException.InvalidNthArgumentType(nParam); - } - } - } + return TypeDescriptionBuilder.OfType(BasicTypes.Boolean).Build(); } [ScriptConstructor] @@ -260,90 +187,153 @@ public static TypeDescription Constructor( IValue p6 = null, IValue p7 = null) { + var builder = new TypeDescriptionBuilder(); + + // параметры, которые заведомо не квалификаторы, заменяем на null, но оставляем, + // чтобы указать номер параметра при выводе ошибки несоответствия типа + var qualifiers = new[] { null, p2, p3, p4, p5, p6, p7 }; + var rawSource = source?.GetRawValue(); - - if (rawSource == null || rawSource.SystemType == BasicTypes.Undefined) + if (rawSource != null && rawSource.SystemType != BasicTypes.Undefined) { - // пустой первый параметр - нет объекта-основания - // добавляемые/вычитаемые типы не допускаются, квалификаторы игнорируются + if (rawSource is TypeDescription typeDesc) + { + // Если 1 парарметр - ОписаниеТипов, то 2 - добавляемые типы, 3 - убираемые типы, + builder.SourceDescription(typeDesc); - // только для контроля типов - var _ = new TypeQualifiersSet(p2, p3, p4, p5, p6, p7); + var typesToAdd = CheckAndParseTypeList(context.TypeManager, p2, 2); + var typesToRemove = CheckAndParseTypeList(context.TypeManager, p3, 3); - return new TypeDescription(); - } + builder.RemoveTypes(typesToRemove); + builder.AddTypes(typesToAdd); - if (rawSource is TypeDescription) + qualifiers[1] = null; // эти параметры не квалификаторы + qualifiers[2] = null; // эти параметры не квалификаторы + } + else if (rawSource.SystemType == BasicTypes.String || rawSource is ArrayImpl) + { + // Если 1 парарметр - Массив или строка, то это набор конкретных типов + // остальные параметры (2 и далее) - клвалификаторы в произвольном порядке + var typesList = CheckAndParseTypeList(context.TypeManager, rawSource, 1); + builder.AddTypes(typesList); + } + else + throw RuntimeException.InvalidArgumentValue(); + } /* else + пустой первый параметр - нет объекта-основания + добавляемые/вычитаемые типы не допускаются, квалификаторы игнорируются + квалификакторы передаются только для контроля типов + */ + CheckAndAddQualifiers(builder, qualifiers); + return builder.Build(); + } + + /// + /// Преобразует входящий параметр в список типов. + /// + /// В качестве типов могут быть переданы Строка или Массив Типов + /// Номер параметра, который будет указан в исключении, если параметр typeList задан неверно + /// Если typeList не может быть разобран как набор типов + /// Список переданных типов, приведенный к конкретным TypeTypeValue + private static List CheckAndParseTypeList(ITypeManager typeManager, IValue types, int nParam) + { + types = types?.GetRawValue(); + if (types == null || types.SystemType == BasicTypes.Undefined) + return new List(); + + if (types.SystemType == BasicTypes.String) { - return ConstructByOtherDescription(context.TypeManager, rawSource, p2, p3, p4, p5, p6, p7); + return FromTypeNames(typeManager, types.AsString()); } - - if (rawSource.SystemType == BasicTypes.String || rawSource is ArrayImpl) + if (types is ArrayImpl arrayOfTypes) { - return ConstructByQualifiers(context.TypeManager, rawSource, p2, p3, p4, p5, p6, p7); + return FromArrayOfTypes(arrayOfTypes); } - throw RuntimeException.InvalidArgumentValue(); + throw RuntimeException.InvalidNthArgumentType(nParam); } - public static TypeDescription ConstructByQualifiers(ITypeManager typeManager, IValue types, - IValue p2 = null, - IValue p3 = null, - IValue p4 = null, - IValue p5 = null, - IValue p6 = null, - IValue p7 = null) + private static List FromTypeNames(ITypeManager typeManager, string types) { - var typesList = ConstructTypeList(typeManager, types); - if (typesList == null) - throw RuntimeException.InvalidNthArgumentType(1); + var typeNames = types.Split(','); + var typesList = new List(); + foreach (var typeName in typeNames) + { + if (string.IsNullOrWhiteSpace(typeName)) + continue; - var qualSet = new TypeQualifiersSet(p2,p3,p4,p5,p6,p7); + var typeValue = new BslTypeValue(typeManager.GetTypeByName(typeName.Trim())); + if (!typesList.Contains(typeValue)) + typesList.Add(typeValue); + } - return new TypeDescription(typesList, - qualSet.numberQualifiers, - qualSet.stringQualifiers, - qualSet.dateQualifiers, - qualSet.binaryDataQualifiers); + return typesList; } - public static TypeDescription ConstructByOtherDescription(ITypeManager typeManager, - IValue typeDescription = null, - IValue addTypes = null, - IValue removeTypes = null, - IValue p4 = null, - IValue p5 = null, - IValue p6 = null, - IValue p7 = null) + private static List FromArrayOfTypes(ArrayImpl arrayOfTypes) { - var removeTypesList = ConstructTypeList(typeManager, removeTypes); - if (removeTypesList == null) - throw RuntimeException.InvalidNthArgumentType(3); - var typesList = new List(); - if (typeDescription is TypeDescription typeDesc) + foreach (var type in arrayOfTypes) { - foreach (var type in typeDesc._types) + if (type.GetRawValue() is BslTypeValue rawType) { - if (!removeTypesList.Contains(type)) - { - typesList.Add(type); - } + typesList.Add(rawType); } } + return typesList; + } - var addTypesList = ConstructTypeList(typeManager, addTypes); - if (addTypesList == null) - throw RuntimeException.InvalidNthArgumentType(2); - typesList.AddRange(addTypesList); + private static void CheckAndAddQualifiers(TypeDescriptionBuilder builder, IValue[] parameters) + { + for (var i = 0; i < parameters.Length; i++) + { + var rawQualifier = parameters[i]?.GetRawValue(); + if (rawQualifier != null && !rawQualifier.Equals(ValueFactory.Create())) + { + CheckAndAddOneQualifier(builder, rawQualifier, i + 1); + } + } + } + + /// + /// Проверяет, что переданный параметр является квалификатором типа. + /// Если тип параметра не является квалификатором, бросает исключение с указанием номера параметра. + /// + /// Построитель описания типов, которому будет присвоен квалификатор + /// Проверяемый входящий параметр + /// Порядковый номер параметра для выброса исключения + /// Если qualifier не является квалификатором типа + private static void CheckAndAddOneQualifier(TypeDescriptionBuilder builder, IValue qualifier, int nParam) + { + switch (qualifier) + { + case NumberQualifiers nq: + builder.SetNumberQualifiers(nq); + break; + + case StringQualifiers sq: + builder.SetStringQualifiers(sq); + break; - var qualSet = new TypeQualifiersSet(null, null, p4, p5, p6, p7); + case DateQualifiers dq: + builder.SetDateQualifiers(dq); + break; - return new TypeDescription(typesList, - qualSet.numberQualifiers, - qualSet.stringQualifiers, - qualSet.dateQualifiers, - qualSet.binaryDataQualifiers); + case BinaryDataQualifiers bdq: + builder.SetBinaryDataQualifiers(bdq); + break; + + default: + throw RuntimeException.InvalidNthArgumentType(nParam); + } + } + } + + internal class UndefinedTypeAdjuster : IValueAdjuster + { + public IValue Adjust(IValue value) + { + return ValueFactory.Create(); } } } diff --git a/src/OneScript.StandardLibrary/TypeDescriptions/TypeDescriptionBuilder.cs b/src/OneScript.StandardLibrary/TypeDescriptions/TypeDescriptionBuilder.cs new file mode 100644 index 000000000..551d8e7d0 --- /dev/null +++ b/src/OneScript.StandardLibrary/TypeDescriptions/TypeDescriptionBuilder.cs @@ -0,0 +1,106 @@ +/*---------------------------------------------------------- +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/. +----------------------------------------------------------*/ + +using System.Collections.Generic; +using System.Linq; +using OneScript.Types; +using OneScript.Values; + +namespace OneScript.StandardLibrary.TypeDescriptions +{ + internal class TypeDescriptionBuilder + { + private NumberQualifiers _numberQualifiers; + private StringQualifiers _stringQualifiers; + private DateQualifiers _dateQualifiers; + private BinaryDataQualifiers _binaryDataQualifiers; + + private const string TYPE_BINARYDATA_NAME = "ДвоичныеДанные"; + + private List _types = new List(); + + internal TypeDescriptionBuilder() + { + } + + public TypeDescriptionBuilder SourceDescription(TypeDescription source) + { + _numberQualifiers = source.NumberQualifiers; + _stringQualifiers = source.StringQualifiers; + _dateQualifiers = source.DateQualifiers; + _binaryDataQualifiers = source.BinaryDataQualifiers; + return AddTypes(source.TypesInternal()); + } + + public TypeDescriptionBuilder AddTypes(IEnumerable types) + { + _types.AddRange(types); + return this; + } + + public TypeDescriptionBuilder RemoveTypes(IEnumerable types) + { + _types.RemoveAll(types.Contains); + return this; + } + + public TypeDescriptionBuilder SetNumberQualifiers(NumberQualifiers nq) + { + _numberQualifiers = nq; + return this; + } + + public TypeDescriptionBuilder SetStringQualifiers(StringQualifiers sq) + { + _stringQualifiers = sq; + return this; + } + + public TypeDescriptionBuilder SetDateQualifiers(DateQualifiers dq) + { + _dateQualifiers = dq; + return this; + } + + public TypeDescriptionBuilder SetBinaryDataQualifiers(BinaryDataQualifiers bq) + { + _binaryDataQualifiers = bq; + return this; + } + + public TypeDescription Build() + { + _types = new List(_types.Distinct()); + _types.RemoveAll(type => type.TypeValue.ImplementingClass == typeof(BslUndefinedValue)); + _types.Sort(new TypeComparer()); + var hasNumber = _types.Any(type => type.TypeValue == BasicTypes.Number); + var hasString =_types.Any(type => type.TypeValue == BasicTypes.String); + var hasDate = _types.Any(type => type.TypeValue == BasicTypes.Date); + var hasBinaryData = _types.Any(x => x.TypeValue.Name == TYPE_BINARYDATA_NAME); + + if (!hasNumber || _numberQualifiers == null) _numberQualifiers = new NumberQualifiers(); + if (!hasString || _stringQualifiers == null) _stringQualifiers = new StringQualifiers(); + if (!hasDate || _dateQualifiers == null) _dateQualifiers = new DateQualifiers(); + if (!hasBinaryData || _binaryDataQualifiers == null) _binaryDataQualifiers = new BinaryDataQualifiers(); + + return new TypeDescription(_types, + _numberQualifiers, + _stringQualifiers, + _dateQualifiers, + _binaryDataQualifiers + ); + + } + + public static TypeDescriptionBuilder OfType(TypeDescriptor commonType) + { + var builder = new TypeDescriptionBuilder(); + builder.AddTypes(new[] { new BslTypeValue(commonType) }); + return builder; + } + } +} \ No newline at end of file diff --git a/tests/typedescription.os b/tests/typedescription.os index d780c3620..8a58a8228 100644 --- a/tests/typedescription.os +++ b/tests/typedescription.os @@ -31,6 +31,14 @@ ВсеТесты.Добавить("ТестДолжен_ПроверитьПриведениеДат"); ВсеТесты.Добавить("ТестДолжен_ПроверитьПриведениеБезПриведения"); ВсеТесты.Добавить("ТестДолжен_ПроверитьПриведениеЧисел"); + ВсеТесты.Добавить("ТестДолжен_ПроверитьПриведениеНеопределено"); + ВсеТесты.Добавить("ТестДолжен_ПроверитьПриведениеОбъектов"); + + ВсеТесты.Добавить("ТестДолжен_Преобразование_ОписаниеБезТипов"); + ВсеТесты.Добавить("ТестДолжен_Преобразование_ОписаниеБезТипов_КвалификаторыИгнорируются"); + + ВсеТесты.Добавить("ТестДолжен_ПроверитьОдинаковыйПорядокТипов"); + ВсеТесты.Добавить("ТестДолжен_ПроверитьПорядокПриведенияТипов"); Возврат ВсеТесты; @@ -445,3 +453,184 @@ юТест.ПроверитьРавенство(Описание.ПривестиЗначение(12345.555), 999.99, "Забивает девятками"); КонецПроцедуры + +Процедура ТестДолжен_Преобразование_ОписаниеБезТипов() Экспорт + + МассивТиповНеопределено = Новый Массив; + МассивТиповНеопределено.Добавить(Тип("Неопределено")); + + ПроверяемыеОписания = Новый СписокЗначений; + ПроверяемыеОписания.Добавить( + Новый ОписаниеТипов, + "Новый ОписаниеТипов" + ); + ПроверяемыеОписания.Добавить( + Новый ОписаниеТипов("Неопределено"), + "Новый ОписаниеТипов(""Неопределено"")" + ); + ПроверяемыеОписания.Добавить( + Новый ОписаниеТипов(МассивТиповНеопределено), + "Новый ОписаниеТипов(МассивТиповНеопределено)" + ); + ПроверяемыеОписания.Добавить( + Новый ОписаниеТипов("Undefined"), + "Новый ОписаниеТипов(""Undefined"")" + ); + + Для Каждого мЭлементПроверки Из ПроверяемыеОписания Цикл + + ОписаниеБезТипов = мЭлементПроверки.Значение; + ОписаниеСлучая = мЭлементПроверки.Представление; + + юТест.ПроверитьРавенство(ОписаниеБезТипов.ПривестиЗначение(), Неопределено, "Приведение без параметра. " + ОписаниеСлучая); + юТест.ПроверитьРавенство(ОписаниеБезТипов.ПривестиЗначение(1), 1, "Приведение числа. " + ОписаниеСлучая); + юТест.ПроверитьРавенство(ОписаниеБезТипов.ПривестиЗначение("1"), "1", "Приведение строки. " + ОписаниеСлучая); + юТест.ПроверитьРавенство(ОписаниеБезТипов.ПривестиЗначение(Тип("Строка")), Тип("Строка"), "Приведение Типа. " + ОписаниеСлучая); + юТест.ПроверитьРавенство(ОписаниеБезТипов.ПривестиЗначение('20230817104356'), '20230817104356', "Приведение даты. " + ОписаниеСлучая); + + ДД = ПолучитьДвоичныеДанныеИзСтроки("Строка"); + юТест.ПроверитьРавенство(ОписаниеБезТипов.ПривестиЗначение(ДД), ДД, "Двоичные данные не ломаются. " + ОписаниеСлучая); + + юТест.ПроверитьРавенство(ОписаниеБезТипов.Типы().Количество(), 0, "Типы() пустой. " + ОписаниеСлучая); + // юТест.ПроверитьЛожь(ОписаниеБезТипов.СодержитТип(Тип("Неопределено")), "Нет типа Неопределено. " + ОписаниеСлучая); + + КонецЦикла; + +КонецПроцедуры + +Процедура ТестДолжен_Преобразование_ОписаниеБезТипов_КвалификаторыИгнорируются() Экспорт + + КЧ = Новый КвалификаторыЧисла(1); + КС = Новый КвалификаторыСтроки(1); + КД = Новый КвалификаторыДаты(ЧастиДаты.Время); + + МассивТиповНеопределено = Новый Массив; + МассивТиповНеопределено.Добавить(Тип("Неопределено")); + + ПроверяемыеОписания = Новый СписокЗначений; + ПроверяемыеОписания.Добавить( + Новый ОписаниеТипов(, КЧ, КС, КД), + "Новый ОписаниеТипов(, КЧ, КС, КД)" + ); + ПроверяемыеОписания.Добавить( + Новый ОписаниеТипов("Неопределено", КЧ, КС, КД), + "Новый ОписаниеТипов(""Неопределено"", КЧ, КС, КД)" + ); + ПроверяемыеОписания.Добавить( + Новый ОписаниеТипов(МассивТиповНеопределено, КЧ, КС, КД), + "Новый ОписаниеТипов(МассивТиповНеопределено, КЧ, КС, КД)" + ); + ПроверяемыеОписания.Добавить( + Новый ОписаниеТипов("Undefined", КЧ, КС, КД), + "Новый ОписаниеТипов(""Undefined"", КЧ, КС, КД)" + ); + + Для Каждого мЭлементПроверки Из ПроверяемыеОписания Цикл + + ОписаниеБезТипов = мЭлементПроверки.Значение; + ОписаниеСлучая = мЭлементПроверки.Представление; + + юТест.ПроверитьРавенство(ОписаниеБезТипов.ПривестиЗначение(), Неопределено, "Приведение без параметра. " + ОписаниеСлучая); + юТест.ПроверитьРавенство(ОписаниеБезТипов.ПривестиЗначение(123), 123, "Число не режется. " + ОписаниеСлучая); // не 1 + юТест.ПроверитьРавенство(ОписаниеБезТипов.ПривестиЗначение("123"), "123", "Строка не режется. " + ОписаниеСлучая); // не "1" + юТест.ПроверитьРавенство(ОписаниеБезТипов.ПривестиЗначение(Тип("Строка")), Тип("Строка"), "Значение типа Тип не ломается. " + ОписаниеСлучая); + юТест.ПроверитьРавенство(ОписаниеБезТипов.ПривестиЗначение('20230817104356'), '20230817104356', "Дата не режется. " + ОписаниеСлучая); // не `00010101104356` + + ДД = ПолучитьДвоичныеДанныеИзСтроки("Строка"); + юТест.ПроверитьРавенство(ОписаниеБезТипов.ПривестиЗначение(ДД), ДД, "Двоичные данные не ломаются. " + ОписаниеСлучая); + + юТест.ПроверитьРавенство(ОписаниеБезТипов.Типы().Количество(), 0, "Типы() пустой. " + ОписаниеСлучая); + юТест.ПроверитьЛожь(ОписаниеБезТипов.СодержитТип(Тип("Неопределено")), "Нет типа Неопределено. " + ОписаниеСлучая); + + КонецЦикла; + +КонецПроцедуры + +Процедура ТестДолжен_ПроверитьПорядокПриведенияТипов() Экспорт + + ОписаниеТипов = Новый ОписаниеТипов("Число, Строка", Новый КвалификаторыСтроки(1)); + + юТест.ПроверитьРавенство(ОписаниеТипов.ПривестиЗначение(Истина), "Д"); // TODO: локализация + юТест.ПроверитьРавенство(ОписаниеТипов.ПривестиЗначение("Строка"), "С"); + юТест.ПроверитьРавенство(ОписаниеТипов.ПривестиЗначение(15), 15); + юТест.ПроверитьРавенство(ОписаниеТипов.ПривестиЗначение('20230911'), "1"); // TODO: локализация + +КонецПроцедуры + +Процедура ТестДолжен_ПроверитьОдинаковыйПорядокТипов() Экспорт + + ОТ = Новый ОписаниеТипов("Число, Строка"); + ПроверитьПорядокТипов(ОТ.Типы(), "Строка, Число"); + + ОТ = Новый ОписаниеТипов("Строка, Число"); + ПроверитьПорядокТипов(ОТ.Типы(), "Строка, Число"); + + ОТ = Новый ОписаниеТипов("Строка, Число, Строка"); + ПроверитьПорядокТипов(ОТ.Типы(), "Строка, Число"); + + ОТ = Новый ОписаниеТипов("Число, Число, Строка"); + ПроверитьПорядокТипов(ОТ.Типы(), "Строка, Число"); + + ОТ = Новый ОписаниеТипов("Число, Число, Строка, Дата, Булево, Неопределено"); + ПроверитьПорядокТипов(ОТ.Типы(), "Булево, Строка, Дата, Число"); + + ОТ = Новый ОписаниеТипов("Неопределено, Число, Дата, Строка, Дата, Булево"); + ПроверитьПорядокТипов(ОТ.Типы(), "Булево, Строка, Дата, Число"); + + ОТ = Новый ОписаниеТипов("ДвоичныеДанные, Неопределено, Тип, NULL, Число, Дата, Строка, Дата, Булево"); + ПроверитьПорядокТипов(ОТ.Типы(), "Булево, ДвоичныеДанные, Строка, Дата, Null, Число, Тип"); + +КонецПроцедуры + +Процедура ТестДолжен_ПроверитьПриведениеНеопределено() Экспорт + + ОТ = Новый ОписаниеТипов("Число, Строка"); + юТест.ПроверитьИстину(ОТ.СодержитТип(Тип("Неопределено")), "Неопределено содержится в описании типов"); + юТест.ПроверитьРавенство(ОТ.Типы().Найти(Тип("Неопределено")), Неопределено, "Неопределено не содержится в типах"); + юТест.ПроверитьРавенство(ОТ.ПривестиЗначение(Неопределено), Неопределено, "Неопределено в неопределено"); + + ОТ = Новый ОписаниеТипов; + юТест.ПроверитьРавенство(ОТ.ПривестиЗначение(Неопределено), Неопределено, "Неопределено в неопределено"); + юТест.ПроверитьЛожь(ОТ.СодержитТип(Тип("Неопределено")), "Неопределено не содержится в описании типов (без типов)"); + юТест.ПроверитьРавенство(ОТ.Типы().Найти(Тип("Неопределено")), Неопределено, "Неопределено не содержится в типах"); + +КонецПроцедуры + +Процедура ТестДолжен_ПроверитьПриведениеОбъектов() Экспорт + + ОТ = Новый ОписаниеТипов("Массив, Структура, Строка"); + + М1 = Новый Массив; + М1.Добавить(1); + М1.Добавить(2); + + М2 = ОТ.ПривестиЗначение(М1); + юТест.ПроверитьРавенство(М2, М1, "Массив тот же самый"); + +КонецПроцедуры + +Процедура ПроверитьПорядокТипов(Знач ТипыОписанияТипов, Знач ОжидаемыйПорядок, Знач Текст = Неопределено) + + Если Текст = Неопределено Тогда + Текст = СтрШаблон("Ожидаемый порядок: %1 + |Полученный порядок: %2", ОжидаемыйПорядок, СтрСоединить(ТипыОписанияТипов, ", ") + ); + КонецЕсли; + + ТипыСтроками = СтрРазделить(ОжидаемыйПорядок, ","); + + юТест.ПроверитьБольшеИлиРавно(ТипыОписанияТипов.Количество(), ТипыСтроками.Количество(), Текст); + + ИндексТипа = 0; + Для Каждого мТипСтрокой Из ТипыСтроками Цикл + + ТипОписания = ТипыОписанияТипов[ИндексТипа]; + ТипОжидаемый = Тип(СокрЛП(мТипСтрокой)); + + юТест.ПроверитьРавенство(ТипОписания, ТипОжидаемый); + + ИндексТипа = ИндексТипа + 1; + + КонецЦикла; + +КонецПроцедуры