diff --git a/.github/workflows/sonar.yml b/.github/workflows/sonar.yml index 3599cd7cb..f41bd6bde 100644 --- a/.github/workflows/sonar.yml +++ b/.github/workflows/sonar.yml @@ -19,14 +19,14 @@ jobs: with: fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis - name: Cache SonarQube packages - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: ~\sonar\cache key: ${{ runner.os }}-sonar restore-keys: ${{ runner.os }}-sonar - name: Cache SonarQube scanner id: cache-sonar-scanner - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: .\.sonar\scanner key: ${{ runner.os }}-sonar-scanner diff --git a/Jenkinsfile b/Jenkinsfile index 813b91da3..aa4829962 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -5,7 +5,7 @@ pipeline { environment { VersionPrefix = '2.0.0' - VersionSuffix = 'rc.9' + VersionSuffix = 'rc.10' outputEnc = '65001' } diff --git a/install/release-notes.md b/install/release-notes.md index 1da6673b3..1cbadb956 100644 --- a/install/release-notes.md +++ b/install/release-notes.md @@ -1,36 +1,19 @@ -# Версия 2.0.0-rc.9 +# Версия 2.0.0-rc.10 -## Новые возможности - -- [#1540](https://github.com/EvilBeaver/OneScript/issues/1540) - Добавлено предупреждение о неявных импортах при компиляции для контроля явного объявления зависимостей -- [#1585](https://github.com/EvilBeaver/OneScript/issues/1585) - Добавлен параметр `ИгнорироватьТипДокумента` при чтении XML -- [#1586](https://github.com/EvilBeaver/OneScript/issues/1586) - Добавлена поддержка пропуска пробельных символов после служебных элементов XML -- [#392](https://github.com/EvilBeaver/OneScript/issues/392) - Метод `ЗаписатьТекущий()` для XML теперь корректно копирует декларацию XML и тип документа -- [#1545](https://github.com/EvilBeaver/OneScript/issues/1545) - Разрешено использование комментариев после аннотаций модуля и в строках с директивой `Использовать` -- [#1593](https://github.com/EvilBeaver/OneScript/issues/1593) - Полностью переработан сервер отладки, возможно переподключение к серверу после завершения сессии отладки. -- Улучшена производительность компиляции большого числа модулей -- Добавлена возможность выполнять attach отладчика внутрь контейнера с 1Script. Предусмотрен маппинг локальных путей и путей внутри контейнера. - -## Исправления ошибок +## Исправления ошибок, обнаруженных в 2.0.0-rc.10 -- [#1573](https://github.com/EvilBeaver/OneScript/issues/1573) - Исправлена работа метода `НайтиСтроки()` для таблицы значений по индексированной колонке с указанным типом -- [#1582](https://github.com/EvilBeaver/OneScript/issues/1582),[#1577](https://github.com/EvilBeaver/OneScript/issues/1577) - Исправлена сортировка чисел и типов в таблице значений -- [#1556](https://github.com/EvilBeaver/OneScript/issues/1556), [#1611](https://github.com/EvilBeaver/OneScript/issues/1611) - Исправлен учет перехода на летнее время в функции `УниверсальноеВремя()`, добавлена поддержка временных зон восточно-европейского времени -- [#1567](https://github.com/EvilBeaver/OneScript/issues/1567) - Исправлено некорректное отображение параметров метода в отладчике -- [#1552](https://github.com/EvilBeaver/OneScript/issues/1552) - Исправлена обработка слова `Ждать` вне асинхронного метода -- [#1603](https://github.com/EvilBeaver/OneScript/issues/1603) - Исправлена работа функции `СтрЗаменить()` -- [#1602](https://github.com/EvilBeaver/OneScript/issues/1602) - Исправлено преобразование элемента списка значений в строку -- [#1542](https://github.com/EvilBeaver/OneScript/issues/1542) - Улучшено позиционирование ошибок в исходном коде -- ряд других ошибок +* Изменено поведение по умолчанию для опции lang.explicitImports под отладкой. Теперь неявные импорты не считаются критичной ошибкой +* #1627: Исправлена ошибка несрабатывания отладчика на коротких скриптах -## Устаревание +## Исправление текущих ошибок -- [#1544](https://github.com/EvilBeaver/OneScript/issues/1544) - Английский вариант перечисления `StreamPosition` объявлен устаревшим в пользу `PositionInStream` +* #1580, #1626: Улучшено соответствие поведения ТаблицыЗначений поведению 1С +* Исправлена медленная вставка строк в индексированную таблицу значений +* -## Технические изменения - -- Выполнен переход на .NET 8. - -## Благодарности +## Новые возможности -Большое спасибо @Mr-Rm, @dmpas, @asosnoviy, @nixel2007, @Bayselonarrend за участие в этом релизе! +* Доступ к сырому сетевому потоку при вызове http-метода. Позволяет организовать http-streaming +* Использование аннотаций внутри параметров аннотаций + +Большое спасибо @Mr-Rm, @dmpas, @asosnoviy, @nixel2007, @Bayselonarrend за участие в этом релизе! \ No newline at end of file diff --git a/src/1Script.sln b/src/1Script.sln index b6efc468b..ee4c3a253 100644 --- a/src/1Script.sln +++ b/src/1Script.sln @@ -65,8 +65,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OneScript.Web.Server", "One EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DocumenterTests", "Tests\DocumenterTests\DocumenterTests.csproj", "{BD385142-E9B4-43C1-8F88-067F24E5AF6D}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VSCode.DebugAdapter.Tests", "Tests\VSCode.DebugAdapter.Tests\VSCode.DebugAdapter.Tests.csproj", "{861F70F4-B10D-4E4E-865C-B8E900391424}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -189,8 +187,8 @@ Global {76F2521D-44D7-48C9-A678-074E22B46092}.LinuxDebug|x86.ActiveCfg = LinuxDebug|Any CPU {76F2521D-44D7-48C9-A678-074E22B46092}.LinuxDebug|x86.Build.0 = LinuxDebug|Any CPU {76F2521D-44D7-48C9-A678-074E22B46092}.Release|Any CPU.ActiveCfg = Release|Any CPU - {76F2521D-44D7-48C9-A678-074E22B46092}.Release|x86.ActiveCfg = Release|Any CPU {76F2521D-44D7-48C9-A678-074E22B46092}.Release|Any CPU.Build.0 = Release|Any CPU + {76F2521D-44D7-48C9-A678-074E22B46092}.Release|x86.ActiveCfg = Release|Any CPU {4FF7C82D-BFEF-415E-81FF-5C0337E99845}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {4FF7C82D-BFEF-415E-81FF-5C0337E99845}.Debug|Any CPU.Build.0 = Debug|Any CPU {4FF7C82D-BFEF-415E-81FF-5C0337E99845}.Debug|x86.ActiveCfg = Debug|Any CPU @@ -333,18 +331,6 @@ Global {BD385142-E9B4-43C1-8F88-067F24E5AF6D}.Release|Any CPU.Build.0 = Release|Any CPU {BD385142-E9B4-43C1-8F88-067F24E5AF6D}.Release|x86.ActiveCfg = Release|Any CPU {BD385142-E9B4-43C1-8F88-067F24E5AF6D}.Release|x86.Build.0 = Release|Any CPU - {861F70F4-B10D-4E4E-865C-B8E900391424}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {861F70F4-B10D-4E4E-865C-B8E900391424}.Debug|Any CPU.Build.0 = Debug|Any CPU - {861F70F4-B10D-4E4E-865C-B8E900391424}.Debug|x86.ActiveCfg = Debug|Any CPU - {861F70F4-B10D-4E4E-865C-B8E900391424}.Debug|x86.Build.0 = Debug|Any CPU - {861F70F4-B10D-4E4E-865C-B8E900391424}.LinuxDebug|Any CPU.ActiveCfg = Debug|Any CPU - {861F70F4-B10D-4E4E-865C-B8E900391424}.LinuxDebug|Any CPU.Build.0 = Debug|Any CPU - {861F70F4-B10D-4E4E-865C-B8E900391424}.LinuxDebug|x86.ActiveCfg = Debug|Any CPU - {861F70F4-B10D-4E4E-865C-B8E900391424}.LinuxDebug|x86.Build.0 = Debug|Any CPU - {861F70F4-B10D-4E4E-865C-B8E900391424}.Release|Any CPU.ActiveCfg = Release|Any CPU - {861F70F4-B10D-4E4E-865C-B8E900391424}.Release|Any CPU.Build.0 = Release|Any CPU - {861F70F4-B10D-4E4E-865C-B8E900391424}.Release|x86.ActiveCfg = Release|Any CPU - {861F70F4-B10D-4E4E-865C-B8E900391424}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -357,7 +343,6 @@ Global {0F5E6099-39BA-41CF-B55F-357F7DF4DE00} = {91059C5B-526C-4B81-B106-99DEFF542D1F} {2F264379-B3B4-44B3-9CBA-A4B0AF3D8785} = {91059C5B-526C-4B81-B106-99DEFF542D1F} {BD385142-E9B4-43C1-8F88-067F24E5AF6D} = {91059C5B-526C-4B81-B106-99DEFF542D1F} - {861F70F4-B10D-4E4E-865C-B8E900391424} = {91059C5B-526C-4B81-B106-99DEFF542D1F} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {A4A871EF-C5A7-478F-907E-31C69A869973} @@ -376,7 +361,4 @@ Global $3.inheritsSet = null $3.scope = application/xaml+xml EndGlobalSection - GlobalSection(Performance) = preSolution - HasPerformanceSessions = true - EndGlobalSection EndGlobal diff --git a/src/OneScript.Core/Commons/Utils.cs b/src/OneScript.Core/Commons/Utils.cs index b110f0713..e64603519 100644 --- a/src/OneScript.Core/Commons/Utils.cs +++ b/src/OneScript.Core/Commons/Utils.cs @@ -35,7 +35,20 @@ public static void ForEach(this IEnumerable input, Action action) action(data); } } - + public static string NameAndValuePresentation(string name, object value) + { + var list = new List(); + if (!string.IsNullOrEmpty(name)) + { + list.Add(name); + } + if (value != null) + { + list.Add(value.ToString()); + } + return string.Join("=", list); + } + public static bool IsMonoRuntime => Type.GetType("Mono.Runtime") != null; } diff --git a/src/OneScript.Core/Contexts/BslAnnotationAttribute.cs b/src/OneScript.Core/Contexts/BslAnnotationAttribute.cs index 446c86a12..eb32971e8 100644 --- a/src/OneScript.Core/Contexts/BslAnnotationAttribute.cs +++ b/src/OneScript.Core/Contexts/BslAnnotationAttribute.cs @@ -5,9 +5,10 @@ This Source Code Form is subject to the terms of the at http://mozilla.org/MPL/2.0/. ----------------------------------------------------------*/ +using OneScript.Commons; +using OneScript.Values; using System; using System.Collections.Generic; -using OneScript.Values; namespace OneScript.Contexts { @@ -37,7 +38,7 @@ public void SetParameters(IEnumerable parameters) public class BslAnnotationParameter { - public BslAnnotationParameter(string name, BslPrimitiveValue value) + public BslAnnotationParameter(string name, BslPrimitiveValue value = null) { Name = name; Value = value; @@ -47,6 +48,10 @@ public BslAnnotationParameter(string name, BslPrimitiveValue value) public BslPrimitiveValue Value { get; } - public int ConstantValueIndex { get; set; } = -1; + public override string ToString() + { + return Utils.NameAndValuePresentation(Name, Value); + } + } } \ No newline at end of file diff --git a/src/OneScript.Core/Exceptions/RuntimeException.cs b/src/OneScript.Core/Exceptions/RuntimeException.cs index acd645c59..63e807fe5 100644 --- a/src/OneScript.Core/Exceptions/RuntimeException.cs +++ b/src/OneScript.Core/Exceptions/RuntimeException.cs @@ -175,8 +175,22 @@ public static RuntimeException InvalidEncoding(string encoding) return new RuntimeException( $"Неправильное имя кодировки '{encoding}'", $"Invalid encoding name '{encoding}'"); + } + + public static RuntimeException IncorrectOffset() + { + return new RuntimeException( + "Неправильное смещение внутри коллекции", + "Incorrect offset within collection"); + } + + public static RuntimeException IndexOutOfRange() + { + return new RuntimeException( + "Значение индекса выходит за пределы диапазона", + "Index is out of range"); } - + #endregion } } \ No newline at end of file diff --git a/src/OneScript.Core/Values/BslAnnotationValue.cs b/src/OneScript.Core/Values/BslAnnotationValue.cs new file mode 100644 index 000000000..88b89b997 --- /dev/null +++ b/src/OneScript.Core/Values/BslAnnotationValue.cs @@ -0,0 +1,58 @@ +/*---------------------------------------------------------- +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 OneScript.Contexts; +using OneScript.Exceptions; +using OneScript.Localization; +using OneScript.Types; +using System.Collections.Generic; +using System.Text; + +namespace OneScript.Values +{ + public sealed class BslAnnotationValue : BslPrimitiveValue + { + public BslAnnotationValue(string name) { + Name = name; + } + + public string Name { get; } + + public List Parameters { get; } = new List(); + + + public override int CompareTo(BslValue other) { + var msg = new BilingualString("Сравнение на больше/меньше для данного типа не поддерживается", + "Comparison for less/greater is not supported for this type"); + + throw new RuntimeException(msg); + } + + public override bool Equals(BslValue other) { + return ReferenceEquals(this, other); + } + + public override string ToString() + { + var sb = new StringBuilder("&"); + sb.Append(Name); + if (Parameters.Count != 0) + { + var prefix = "("; + foreach (var parameter in Parameters) + { + sb.Append(prefix); + sb.Append(parameter); + prefix = ","; + } + sb.Append(")"); + } + return sb.ToString(); + } + } +} \ No newline at end of file diff --git a/src/OneScript.Core/Values/BslUndefinedValue.cs b/src/OneScript.Core/Values/BslUndefinedValue.cs index d86f0ade3..95324e00a 100644 --- a/src/OneScript.Core/Values/BslUndefinedValue.cs +++ b/src/OneScript.Core/Values/BslUndefinedValue.cs @@ -1,7 +1,7 @@ /*---------------------------------------------------------- -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 +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/. ----------------------------------------------------------*/ @@ -24,6 +24,11 @@ public override bool Equals(BslValue other) return ReferenceEquals(Instance, other); } + public override int GetHashCode() + { + return 42; // Константа для синглтона + } + public override string ToString() => string.Empty; } } \ No newline at end of file diff --git a/src/OneScript.DebugServices/Internal/ConnectableSessionProxy.cs b/src/OneScript.DebugServices/Internal/ConnectableSessionProxy.cs index 8af1bc24d..6c5b6378c 100644 --- a/src/OneScript.DebugServices/Internal/ConnectableSessionProxy.cs +++ b/src/OneScript.DebugServices/Internal/ConnectableSessionProxy.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.Diagnostics; using System.Threading; using ScriptEngine.Machine; using ScriptEngine.Machine.Debugger; @@ -53,6 +54,11 @@ public void WaitReadyToRun() } _connectionEvent.Wait(); + Debug.Assert(_isConnected, "Must be connected"); + Debug.Assert(_session is DebugSession, "Session must be DebugSession"); + + // Делегируем ожидание реальной сессии + _session.WaitReadyToRun(); } public bool IsActive => _session.IsActive; diff --git a/src/OneScript.Language/Localization/BilingualString.cs b/src/OneScript.Language/Localization/BilingualString.cs index baed18d03..62da2b570 100644 --- a/src/OneScript.Language/Localization/BilingualString.cs +++ b/src/OneScript.Language/Localization/BilingualString.cs @@ -73,5 +73,15 @@ public static string Localize(string russian, string english) return russian; } + } + + public static class BilingualStringExtension + { + public static bool BilingualEquals(this string str, string lang1, string lang2, + StringComparison comparison = StringComparison.CurrentCultureIgnoreCase) + { + return string.Equals(str, lang1, comparison) || string.Equals(str, lang2, comparison); + } } + } \ No newline at end of file diff --git a/src/OneScript.Language/SyntaxAnalysis/AstNodes/AnnotationParameterNode.cs b/src/OneScript.Language/SyntaxAnalysis/AstNodes/AnnotationParameterNode.cs index 084d29895..4c1669784 100644 --- a/src/OneScript.Language/SyntaxAnalysis/AstNodes/AnnotationParameterNode.cs +++ b/src/OneScript.Language/SyntaxAnalysis/AstNodes/AnnotationParameterNode.cs @@ -17,19 +17,29 @@ public AnnotationParameterNode() : base(NodeKind.AnnotationParameter) protected override void OnChildAdded(BslSyntaxNode child) { - var node = (TerminalNode) child; - if (child.Kind == NodeKind.AnnotationParameterName) + if (child.Kind == NodeKind.Annotation) { - Name = node.Lexem.Content; + AnnotationNode = (AnnotationNode)child; } - if (child.Kind == NodeKind.AnnotationParameterValue) + else { - Value = node.Lexem; + var node = (TerminalNode)child; + if (child.Kind == NodeKind.AnnotationParameterName) + { + Name = node.Lexem.Content; + } + if (child.Kind == NodeKind.AnnotationParameterValue) + { + Value = node.Lexem; + } } } public string Name { get; private set; } public Lexem Value { get; private set; } + + public AnnotationNode AnnotationNode { get; private set; } + } } \ No newline at end of file diff --git a/src/OneScript.Language/SyntaxAnalysis/DefaultBslParser.cs b/src/OneScript.Language/SyntaxAnalysis/DefaultBslParser.cs index ee986e78c..7f6b980ca 100644 --- a/src/OneScript.Language/SyntaxAnalysis/DefaultBslParser.cs +++ b/src/OneScript.Language/SyntaxAnalysis/DefaultBslParser.cs @@ -541,13 +541,18 @@ private void BuildAnnotations() { while (_lastExtractedLexem.Type == LexemType.Annotation) { - var node = new AnnotationNode(NodeKind.Annotation, _lastExtractedLexem); + var node = BuildAnnotationDefinition(); _annotations.Add(node); - NextLexem(); - BuildAnnotationParameters(node); } } - + private AnnotationNode BuildAnnotationDefinition() { + var node = new AnnotationNode(NodeKind.Annotation, _lastExtractedLexem); + NextLexem(); + BuildAnnotationParameters(node); + return node; + } + + private void BuildAnnotationParameters(AnnotationNode annotation) { if (_lastExtractedLexem.Token != Token.OpenPar) @@ -599,11 +604,16 @@ private void BuildAnnotationParameter(AnnotationNode annotation) private bool BuildAnnotationParamValue(AnnotationParameterNode annotationParam) { + if (_lastExtractedLexem.Type == LexemType.Annotation) { + var annotation = BuildAnnotationDefinition(); + annotationParam.AddChild(annotation); + return true; + } return BuildDefaultParameterValue(annotationParam, NodeKind.AnnotationParameterValue); } - + #endregion - + private void BuildCodeBatch(params Token[] endTokens) { PushStructureToken(endTokens); diff --git a/src/OneScript.Native/Compiler/CompilerHelpers.cs b/src/OneScript.Native/Compiler/CompilerHelpers.cs index 2afe69439..e8cc930a1 100644 --- a/src/OneScript.Native/Compiler/CompilerHelpers.cs +++ b/src/OneScript.Native/Compiler/CompilerHelpers.cs @@ -90,6 +90,16 @@ private static IEnumerable GetAnnotationParameters(Annot private static BslAnnotationParameter MakeAnnotationParameter(AnnotationParameterNode param) { BslAnnotationParameter result; + if (param.AnnotationNode != null) + { + var runtimeValue = new BslAnnotationValue(param.AnnotationNode.Name); + foreach (var child in param.AnnotationNode.Children) + { + runtimeValue.Parameters.Add(MakeAnnotationParameter((AnnotationParameterNode)child)); + } + result = new BslAnnotationParameter(param.Name, runtimeValue); + } + else if (param.Value.Type != LexemType.NotALexem) { var runtimeValue = ValueFromLiteral(param.Value); diff --git a/src/OneScript.StandardLibrary/Binary/BinaryDataBuffer.cs b/src/OneScript.StandardLibrary/Binary/BinaryDataBuffer.cs index fd4ce01f6..1509059fc 100644 --- a/src/OneScript.StandardLibrary/Binary/BinaryDataBuffer.cs +++ b/src/OneScript.StandardLibrary/Binary/BinaryDataBuffer.cs @@ -246,7 +246,7 @@ public void WriteInt64(int position, BslValue value, BslValue byteOrder = null) private void WriteBitwiseOp(int position, BinaryDataBuffer buffer, int number, Func op) { if(position < 0) - throw new IndexOutOfRangeException("Значение индекса выходит за границы диапазона"); + throw RuntimeException.IndexOutOfRange(); try { diff --git a/src/OneScript.StandardLibrary/Collections/ArrayImpl.cs b/src/OneScript.StandardLibrary/Collections/ArrayImpl.cs index e26b26f61..388125736 100644 --- a/src/OneScript.StandardLibrary/Collections/ArrayImpl.cs +++ b/src/OneScript.StandardLibrary/Collections/ArrayImpl.cs @@ -99,7 +99,7 @@ public void Add(IValue value = null) public void Insert(int index, IValue value = null) { if (index < 0) - throw IndexOutOfBoundsException(); + throw RuntimeException.IndexOutOfRange(); if (index > _values.Count) Extend(index - _values.Count); @@ -128,7 +128,7 @@ public IValue Find(IValue what) public void Remove(int index) { if (index < 0 || index >= _values.Count) - throw IndexOutOfBoundsException(); + throw RuntimeException.IndexOutOfRange(); _values.RemoveAt(index); } @@ -143,7 +143,7 @@ public int UpperBound() public IValue Get(int index) { if (index < 0 || index >= _values.Count) - throw IndexOutOfBoundsException(); + throw RuntimeException.IndexOutOfRange(); return _values[index]; } @@ -152,7 +152,7 @@ public IValue Get(int index) public void Set(int index, IValue value) { if (index < 0 || index >= _values.Count) - throw IndexOutOfBoundsException(); + throw RuntimeException.IndexOutOfRange(); _values[index] = value; } @@ -234,10 +234,5 @@ public static ArrayImpl Constructor(FixedArrayImpl fixedArray) { return new ArrayImpl(fixedArray); } - - private static RuntimeException IndexOutOfBoundsException() - { - return new RuntimeException("Значение индекса выходит за пределы диапазона"); - } } } diff --git a/src/OneScript.StandardLibrary/Collections/Indexes/CollectionIndex.cs b/src/OneScript.StandardLibrary/Collections/Indexes/CollectionIndex.cs index 7e6d7d977..10a415399 100644 --- a/src/OneScript.StandardLibrary/Collections/Indexes/CollectionIndex.cs +++ b/src/OneScript.StandardLibrary/Collections/Indexes/CollectionIndex.cs @@ -21,8 +21,8 @@ public class CollectionIndex : AutoCollectionContext private readonly List _fields = new List(); private readonly IIndexCollectionSource _source; - private readonly IDictionary> _data = - new Dictionary>(); + private readonly IDictionary> _data = + new Dictionary>(); public CollectionIndex(IIndexCollectionSource source, IEnumerable fields) { @@ -48,7 +48,7 @@ public override string ToString() public IEnumerable GetData(PropertyNameIndexAccessor searchCriteria) { var key = IndexKey(searchCriteria); - return _data.TryGetValue(key, out var filteredData) ? filteredData : new List(); + return _data.TryGetValue(key, out var filteredData) ? filteredData : Enumerable.Empty(); } internal void FieldRemoved(IValue field) @@ -63,22 +63,22 @@ internal void FieldRemoved(IValue field) internal void ElementAdded(PropertyNameIndexAccessor element) { var key = CollectionIndexKey.Extract(element, _fields); - if (_data.TryGetValue(key, out var list)) + if (_data.TryGetValue(key, out var set)) { - list.Add(element); + set.Add(element); } else { - _data.Add(key, new List { element}); + _data.Add(key, new HashSet { element }); } } internal void ElementRemoved(PropertyNameIndexAccessor element) { var key = CollectionIndexKey.Extract(element, _fields); - if (_data.TryGetValue(key, out var value)) + if (_data.TryGetValue(key, out var set)) { - value.Remove(element); + set.Remove(element); } } diff --git a/src/OneScript.StandardLibrary/Collections/Indexes/CollectionIndexKey.cs b/src/OneScript.StandardLibrary/Collections/Indexes/CollectionIndexKey.cs index ea78eeeb6..6e716a355 100644 --- a/src/OneScript.StandardLibrary/Collections/Indexes/CollectionIndexKey.cs +++ b/src/OneScript.StandardLibrary/Collections/Indexes/CollectionIndexKey.cs @@ -57,7 +57,7 @@ public override bool Equals(object obj) foreach (var key in allKeys) { var thisValue = _values[key]; - var otherValue = _values[key]; + var otherValue = casted._values[key]; if (!thisValue.Equals(otherValue)) return false; } diff --git a/src/OneScript.StandardLibrary/Collections/ValueList/ValueListImpl.cs b/src/OneScript.StandardLibrary/Collections/ValueList/ValueListImpl.cs index e51486826..6f3c1b288 100644 --- a/src/OneScript.StandardLibrary/Collections/ValueList/ValueListImpl.cs +++ b/src/OneScript.StandardLibrary/Collections/ValueList/ValueListImpl.cs @@ -212,7 +212,7 @@ private int IndexByValue(BslValue item) } if (index < 0 || index >= _items.Count()) - throw new RuntimeException("Значение индекса выходит за пределы диапазона"); + throw RuntimeException.IndexOutOfRange(); } return index; diff --git a/src/OneScript.StandardLibrary/Collections/ValueTable/ValueTable.cs b/src/OneScript.StandardLibrary/Collections/ValueTable/ValueTable.cs index 5c59332c9..52ae1e800 100644 --- a/src/OneScript.StandardLibrary/Collections/ValueTable/ValueTable.cs +++ b/src/OneScript.StandardLibrary/Collections/ValueTable/ValueTable.cs @@ -5,18 +5,19 @@ 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; -using OneScript.StandardLibrary.Collections.Indexes; using OneScript.Exceptions; using OneScript.Execution; +using OneScript.Localization; +using OneScript.StandardLibrary.Collections.Exceptions; +using OneScript.StandardLibrary.Collections.Indexes; using OneScript.Types; using OneScript.Values; using ScriptEngine.Machine; using ScriptEngine.Machine.Contexts; -using OneScript.StandardLibrary.Collections.Exceptions; +using System; +using System.Collections.Generic; +using System.Linq; namespace OneScript.StandardLibrary.Collections.ValueTable { @@ -33,8 +34,8 @@ public ValueTable() { Columns = new ValueTableColumnCollection(this); _rows = new List(); - Indexes = new CollectionIndexes(this); - } + Indexes = new CollectionIndexes(this); + } /// /// Коллекция колонок @@ -76,13 +77,18 @@ public ValueTableRow Add() /// /// Вставляет строку в указанную позицию /// - /// Число - Индекс позиции куда будет произведена вставка + /// Число - Индекс позиции куда будет произведена вставка. + /// Если индекс вне размера Таблицы значений, строка добавляется в конец /// СтрокаТаблицыЗначений [ContextMethod("Вставить", "Insert")] public ValueTableRow Insert(int index) { var row = new ValueTableRow(this); - _rows.Insert(index, row); + if (index < 0 || index > _rows.Count) + _rows.Add(row); // для совместимости с 1С, хотя логичней было бы исключение + else + _rows.Insert(index, row); + Indexes.ElementAdded(row); return row; } @@ -116,15 +122,16 @@ public void LoadColumn(IValue values, IValue columnIndex) { // ValueTableColumn Column = Columns.GetColumnByIIndex(ColumnIndex); var row_iterator = _rows.GetEnumerator(); - var array_iterator = (values as ArrayImpl).GetEnumerator(); + var array_iterator = (values as ArrayImpl)?.GetEnumerator() + ?? throw RuntimeException.InvalidNthArgumentType(1); - Indexes.ClearIndexes(); - + Indexes.ClearIndexes(); + while (row_iterator.MoveNext() && array_iterator.MoveNext()) { row_iterator.Current.Set(columnIndex, array_iterator.Current); - } - + } + Indexes.Rebuild(); } @@ -150,33 +157,33 @@ public ArrayImpl UnloadColumn(IValue column) return result; } - private List GetProcessingColumnList(string ColumnNames, bool EmptyListInCaseOfNull = false) + private List GetProcessingColumnList(string columnNames, bool emptyListInCaseOfNull = false) { - List processing_list = new List(); - if (ColumnNames != null) + var processing_list = new List(); + if (string.IsNullOrEmpty(columnNames)) // Передали пустую строку вместо списка колонок + { + if (!emptyListInCaseOfNull) + { + processing_list.AddRange(Columns); + } + return processing_list; + } + + foreach (var column_name in columnNames.Split(',')) { - if (ColumnNames.Trim().Length == 0) - { - // Передали пустую строку вместо списка колонок - return processing_list; - } + if (column_name == String.Empty) + continue; - foreach (var column_name in ColumnNames.Split(',')) - { - var name = column_name.Trim(); - var Column = Columns.FindColumnByName(name); + var name = column_name.Trim(); - if (Column == null) - throw ColumnException.WrongColumnName(name); + var Column = Columns.FindColumnByName(name); + if (Column == null) + throw ColumnException.WrongColumnName(column_name); - if (processing_list.Find( x=> x.Name==name ) == null) - processing_list.Add(Column); - } - } - else if (!EmptyListInCaseOfNull) - { - processing_list.AddRange(Columns); - } + if (processing_list.Find(x => x.Name == name) == null) + processing_list.Add(Column); + } + return processing_list; } @@ -184,7 +191,8 @@ private List GetProcessingColumnList(string ColumnNames, bool /// Заполнить колонку/колонки указанным значением /// /// Произвольный - Устанавливаемое значение - /// Строка - Список имен колонок для установки значения (разделены запятыми) + /// Строка - Список имен колонок для установки значения (разделены запятыми). + /// Если параметр не указан или передана пустая строка, будут заполнены все колонки [ContextMethod("ЗаполнитьЗначения", "FillValues")] public void FillValues(IValue value, string columnNames = null) { @@ -211,9 +219,9 @@ public int IndexOf(IValue row) if (row is ValueTableRow tableRow) return _rows.IndexOf(tableRow); - return -1; - } - + throw RuntimeException.InvalidArgumentType(); + } + /// /// Сумма значений всех строк указанной колонки /// @@ -222,25 +230,65 @@ public int IndexOf(IValue row) /// Число - Индекс колонки для суммирования /// КолонкаТаблицыЗначений - Колонка для суммирования /// + /// + /// Если в колонке установлен тип и он единственный, + /// то при суммировании будет попытка преобразования значения к типу Число. + ///
Если колонке не присвоены типы + /// или в колонке несколько типов и среди них есть тип Число, + /// то в суммироваться будут только значения типа Число + ///
Если в колонке несколько типов и среди них нет типа Число, то результатом будет Неопределено. + ///
/// Число [ContextMethod("Итог", "Total")] public IValue Total(IValue columnIndex) { - var Column = Columns.GetColumnByIIndex(columnIndex); - bool has_data = false; - decimal Result = 0; + var column = Columns.GetColumnByIIndex(columnIndex); + + var types = column.ValueType.Types(); + if (types.Count() == 1) // единственный тип + { + return TotalAllAsNumber(column); + } + + if (types.Count() == 0 // нет типов + || types.Any(x => ((BslTypeValue)x).TypeValue == BasicTypes.Number)) // среди типов есть Число + { + return TotalNumbersOnly(column); + } + + // несколько типов и нет типа Число + return ValueFactory.Create(); + } - foreach (var row in _rows) - { - var current_value = row.Get(Column); - if (current_value.SystemType == BasicTypes.Number) - { - has_data = true; - Result += current_value.AsNumber(); - } - } - - return has_data ? ValueFactory.Create(Result) : ValueFactory.Create(); + private IValue TotalAllAsNumber(ValueTableColumn column) + { + decimal result = 0; + foreach (var row in _rows) + { + try + { + result += row.Get(column).AsNumber(); + } + catch (RuntimeException) + { + // игнорировать неприводимые к числу + } + } + return ValueFactory.Create(result); + } + + private IValue TotalNumbersOnly(ValueTableColumn column) + { + decimal result = 0; + foreach (var row in _rows) + { + var current_value = row.Get(column); + if (current_value.SystemType == BasicTypes.Number) + { + result += current_value.AsNumber(); + } + } + return ValueFactory.Create(result); } /// @@ -296,8 +344,8 @@ public ArrayImpl FindRows(StructureImpl filter) var mapped = ColumnsMap(filter); var suitableIndex = Indexes.FindSuitableIndex(mapped.Keys()); - var dataToScan = suitableIndex != null ? suitableIndex.GetData(mapped) : _rows; - + var dataToScan = suitableIndex != null ? suitableIndex.GetData(mapped) : _rows; + foreach (var element in dataToScan) { var row = (ValueTableRow)element; @@ -314,6 +362,9 @@ private MapImpl ColumnsMap(StructureImpl filter) foreach (var kv in filter) { var key = Columns.FindColumnByName(kv.Key.ToString()); + if (key == null) + throw ColumnException.WrongColumnName(kv.Key.ToString()); + result.Insert(key, kv.Value); } @@ -339,7 +390,7 @@ public void Clear() public ValueTableRow Get(int index) { if (index < 0 || index >= Count()) - throw RuntimeException.InvalidArgumentValue(); + throw RuntimeException.IndexOutOfRange(); return _rows[index]; } @@ -390,8 +441,8 @@ public void GroupBy(IBslProcess process, string groupColumnNames, string aggrega private static void CheckMixedColumns(List groupColumns, List aggregateColumns) { - foreach (var groupColumn in groupColumns ) - if ( aggregateColumns.Find(x => x.Name==groupColumn.Name)!=null ) + foreach (var groupColumn in groupColumns) + if (aggregateColumns.Find(x => x.Name == groupColumn.Name) != null) throw ColumnException.ColumnsMixed(groupColumn.Name); } @@ -401,7 +452,7 @@ private static void CopyRowData(ValueTableRow source, ValueTableRow dest, IEnume dest.Set(column, source.Get(column)); } - private void AppendRowData(ValueTableRow source, ValueTableRow dest, IEnumerable columns) + private static void AppendRowData(ValueTableRow source, ValueTableRow dest, IEnumerable columns) { foreach (var column in columns) { @@ -420,7 +471,7 @@ private static decimal GetNumeric(ValueTableRow row, ValueTableColumn column) private class RowsByColumnsEqComparer : IEqualityComparer { private readonly IBslProcess _process; - private List _columns; + private readonly List _columns; public RowsByColumnsEqComparer(IBslProcess process, List columns) { @@ -455,7 +506,7 @@ private int IndexByValue(BslValue item) { index = IndexOf(row); if (index == -1) - throw new RuntimeException("Строка не принадлежит таблице значений"); + throw ValueTableException.RowDoesntBelongTo(); } else { @@ -469,7 +520,7 @@ private int IndexByValue(BslValue item) } if (index < 0 || index >= _rows.Count) - throw new RuntimeException("Значение индекса выходит за пределы диапазона"); + throw RuntimeException.IndexOutOfRange(); } return index; @@ -482,7 +533,8 @@ private int IndexByValue(BslValue item) /// СтрокаТаблицыЗначений - Строка которую сдвигаем /// Число - Индекс сдвигаемой строки /// - /// Количество строк, на которое сдвигается строка. Если значение положительное - сдвиг вниз, иначе вверх + /// Количество строк, на которое сдвигается строка. + /// Если значение положительное - сдвиг вниз, иначе вверх [ContextMethod("Сдвинуть", "Move")] public void Move(BslValue row, int offset) { @@ -491,7 +543,7 @@ public void Move(BslValue row, int offset) int index_dest = index_source + offset; if (index_dest < 0 || index_dest >= _rows.Count) - throw RuntimeException.InvalidNthArgumentValue(2); + throw RuntimeException.IncorrectOffset(); ValueTableRow tmp = _rows[index_source]; @@ -510,7 +562,8 @@ public void Move(BslValue row, int offset) /// /// Создает новую таблицу значений с указанными колонками. Данные не копируются. /// - /// Строка - Имена колонок для копирования, разделены запятыми + /// Строка - Имена колонок для копирования, разделены запятыми + /// Если параметр не указан или передана пустая строка, будут скопированы все колонки /// ТаблицаЗначений [ContextMethod("СкопироватьКолонки", "CopyColumns")] public ValueTable CopyColumns(string columnNames = null) @@ -540,59 +593,43 @@ public ValueTable CopyColumns(string columnNames = null) [ContextMethod("Скопировать", "Copy")] public ValueTable Copy(IValue rows = null, string columnNames = null) { - var Result = CopyColumns(columnNames); - var columns = GetProcessingColumnList(columnNames); - - IEnumerable requestedRows; - if (rows == null) - { - requestedRows = _rows; - } - else - { - if (rows is StructureImpl structure) - requestedRows = FindRows(structure).Select(x => x as ValueTableRow); - else if (rows is ArrayImpl array) - requestedRows = GetRowsEnumByArray(array); - else - throw RuntimeException.InvalidArgumentType(); - } + var result = CopyColumns(columnNames); + var columns = GetProcessingColumnList(columnNames); + + IEnumerable requestedRows = rows switch + { + null => _rows, + StructureImpl structure => FindRows(structure).Select(x => x as ValueTableRow), + ArrayImpl array => GetRowsEnumByArray(array), + _ => throw RuntimeException.InvalidArgumentType(), + }; var columnMap = new Dictionary(); foreach (var column in columns) { - var destinationColumn = Result.Columns.FindColumnByName(column.Name); + var destinationColumn = result.Columns.FindColumnByName(column.Name); columnMap.Add(column, destinationColumn); } foreach (var row in requestedRows) { - var new_row = Result.Add(); + var new_row = result.Add(); foreach (var Column in columns) { new_row.Set(columnMap[Column], row.Get(Column)); } } - return Result; + return result; } - private IEnumerable GetRowsEnumByArray(IValue rows) - { - IEnumerable requestedRows; - var rowsArray = rows as ArrayImpl; + private IEnumerable GetRowsEnumByArray(ArrayImpl rowsArray) + { if (rowsArray == null) throw RuntimeException.InvalidArgumentType(); - requestedRows = rowsArray.Select(x => - { - var vtr = x as ValueTableRow; - if (vtr == null || vtr.Owner() != this) - throw RuntimeException.InvalidArgumentValue(); - - return vtr; - }); - return requestedRows; + return rowsArray.Select(x => x is ValueTableRow vtr && vtr.Owner() == this ? vtr + : throw RuntimeException.InvalidArgumentValue()); } private struct ValueTableSortRule @@ -610,24 +647,23 @@ private List GetSortRules(string Columns) foreach (string column in a_columns) { - string[] description = column.Trim().Split(' '); + string[] description = column.Trim().Split(' ', StringSplitOptions.RemoveEmptyEntries); if (description.Length == 0) throw ColumnException.WrongColumnName(); - - ValueTableSortRule Desc = new ValueTableSortRule(); - Desc.Column = this.Columns.FindColumnByName(description[0]); - - if (description.Length > 1) - { - if (String.Compare(description[1], "DESC", true) == 0 || String.Compare(description[1], "УБЫВ", true) == 0) - Desc.direction = -1; - else - Desc.direction = 1; - } - else - Desc.direction = 1; - - Rules.Add(Desc); + if (description.Length > 2) + throw RuntimeException.InvalidNthArgumentValue(1); + + var sortColumn = this.Columns.FindColumnByName(description[0]); + if (sortColumn == null) + throw ColumnException.WrongColumnName(description[0]); + + var rule = new ValueTableSortRule + { + Column = sortColumn, + direction = (description.Length > 1 && description[1].BilingualEquals("УБЫВ", "DESC")) ? -1 : 1 + }; + + Rules.Add(rule); } return Rules; @@ -644,8 +680,8 @@ public RowComparator(IBslProcess process, List Rules) if (Rules.Count == 0) throw RuntimeException.InvalidArgumentValue(); - this.Rules = Rules; - _comparer = new GenericIValueComparer(process); + this.Rules = Rules; + _comparer = new GenericIValueComparer(process); } private int OneCompare(ValueTableRow x, ValueTableRow y, ValueTableSortRule Rule) @@ -707,8 +743,8 @@ public override IEnumerator GetEnumerator() { yield return item; } - } - + } + public override IValue GetIndexedValue(IValue index) { return Get((int)index.AsNumber()); @@ -731,5 +767,24 @@ public IValue GetField(string name) { return Columns.FindColumnByName(name); } - } + } + + public sealed class ValueTableException : RuntimeException + { + public ValueTableException(BilingualString message, Exception innerException) : base(message, + innerException) + { + } + + public ValueTableException(BilingualString message) : base(message) + { + } + + public static ValueTableException RowDoesntBelongTo() + { + return new ValueTableException(new BilingualString( + "Строка не принадлежит таблице значений", + "Row does not belong to table")); + } + } } diff --git a/src/OneScript.StandardLibrary/Collections/ValueTable/ValueTableColumnCollection.cs b/src/OneScript.StandardLibrary/Collections/ValueTable/ValueTableColumnCollection.cs index aaeb48e78..288adf683 100644 --- a/src/OneScript.StandardLibrary/Collections/ValueTable/ValueTableColumnCollection.cs +++ b/src/OneScript.StandardLibrary/Collections/ValueTable/ValueTableColumnCollection.cs @@ -7,7 +7,6 @@ This Source Code Form is subject to the terms of the using System; using System.Collections.Generic; -using System.Linq; using OneScript.Commons; using OneScript.Contexts; using OneScript.Exceptions; @@ -46,7 +45,10 @@ public ValueTableColumnCollection(ValueTable owner) /// КолонкаТаблицыЗначений [ContextMethod("Добавить", "Add")] public ValueTableColumn Add(string name, TypeDescription type = null, string title = null, int width = 0) - { + { + if (!Utils.IsValidIdentifier(name)) + throw ColumnException.WrongColumnName(name); + if (FindColumnByName(name) != null) throw ColumnException.DuplicatedColumnName(name); @@ -68,6 +70,9 @@ public ValueTableColumn Add(string name, TypeDescription type = null, string tit [ContextMethod("Вставить", "Insert")] public ValueTableColumn Insert(int index, string name, TypeDescription type = null, string title = null, int width = 0) { + if (!Utils.IsValidIdentifier(name)) + throw ColumnException.WrongColumnName(name); + if (FindColumnByName(name) != null) throw ColumnException.DuplicatedColumnName(name); @@ -126,7 +131,7 @@ public IValue Find(string name) public void Delete(IValue column) { var vtColumn = GetColumnByIIndex(column); - _owner.ForEach((ValueTableRow x)=> + _owner.ForEach((ValueTableRow x) => { x.OnOwnerColumnRemoval(vtColumn); }); @@ -140,7 +145,7 @@ public void Delete(IValue column) [ContextMethod("Очистить", "Clear")] public void Clear() { - while (_columns.Any()) + while (_columns.Count != 0) { Delete(_columns[0]); } @@ -151,10 +156,13 @@ public ValueTableColumn FindColumnByName(string name) return _columns.Find(column => _namesComparer.Equals(name, column.Name)); } - public ValueTableColumn FindColumnByIndex(int index) - { + public ValueTableColumn FindColumnByIndex(int index) + { + if (index < 0 || index >= _columns.Count) + throw RuntimeException.IndexOutOfRange(); return _columns[index]; - } + } + public IEnumerator GetEnumerator() { @@ -171,10 +179,7 @@ System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() public override bool IsIndexed => true; - public override IValue GetIndexedValue(IValue index) - { - return GetColumnByIIndex(index); - } + public override IValue GetIndexedValue(IValue index) => GetColumnByIIndex(index); public override int GetPropertyNumber(string name) { @@ -184,11 +189,8 @@ public override int GetPropertyNumber(string name) return idx; } - public override int GetPropCount() - { - return _columns.Count; - } - + public override int GetPropCount() => _columns.Count; + public override string GetPropName(int propNum) { return FindColumnByIndex(propNum).Name; @@ -199,39 +201,26 @@ public override IValue GetPropValue(int propNum) return FindColumnByIndex(propNum); } - public override bool IsPropWritable(int propNum) - { - return false; - } - - public override bool IsPropReadable(int propNum) - { - return true; - } + public override bool IsPropWritable(int propNum) => false; + + public override bool IsPropReadable(int propNum) => true; public ValueTableColumn GetColumnByIIndex(IValue index) { if (index.SystemType == BasicTypes.String) { - ValueTableColumn Column = FindColumnByName(index.ToString()); - if (Column == null) - throw PropertyAccessException.PropNotFoundException(index.ToString()); - return Column; + return FindColumnByName(index.ToString()) + ?? throw PropertyAccessException.PropNotFoundException(index.ToString()); } if (index.SystemType == BasicTypes.Number) { - int i_index = Decimal.ToInt32(index.AsNumber()); - if (i_index < 0 || i_index >= Count()) - throw RuntimeException.InvalidArgumentValue(); - - ValueTableColumn Column = FindColumnByIndex(i_index); - return Column; + return FindColumnByIndex(decimal.ToInt32(index.AsNumber())); } - if (index is ValueTableColumn) + if (index is ValueTableColumn column) { - return index as ValueTableColumn; + return column; } throw RuntimeException.InvalidArgumentType(); @@ -248,13 +237,12 @@ public int GetColumnNumericIndex(IValue index) { int iIndex = Decimal.ToInt32(index.AsNumber()); if (iIndex < 0 || iIndex >= Count()) - throw RuntimeException.InvalidArgumentValue(); + throw RuntimeException.IndexOutOfRange(); return iIndex; } - var column = index as ValueTableColumn; - if (column != null) + if (index is ValueTableColumn column) { return IndexOf(column); } diff --git a/src/OneScript.StandardLibrary/Collections/ValueTable/ValueTableRow.cs b/src/OneScript.StandardLibrary/Collections/ValueTable/ValueTableRow.cs index fdc10f6ed..a7a13aa93 100644 --- a/src/OneScript.StandardLibrary/Collections/ValueTable/ValueTableRow.cs +++ b/src/OneScript.StandardLibrary/Collections/ValueTable/ValueTableRow.cs @@ -16,7 +16,7 @@ namespace OneScript.StandardLibrary.Collections.ValueTable [ContextClass("СтрокаТаблицыЗначений", "ValueTableRow")] public class ValueTableRow : AutoContext, ICollectionContext, IDebugPresentationAcceptor { - private readonly Dictionary _data = new Dictionary(); + private readonly Dictionary _data = new Dictionary(); private readonly ValueTable _owner; public ValueTableRow(ValueTable owner) @@ -26,7 +26,7 @@ public ValueTableRow(ValueTable owner) public int Count() { - return Owner().Columns.Count(); + return _owner.Columns.Count(); } public int Count(IBslProcess process) => Count(); @@ -43,12 +43,11 @@ public ValueTable Owner() private IValue TryValue(ValueTableColumn Column) { - IValue Value; - if (_data.TryGetValue(Column, out Value)) - { - return Value; - } - return Column.ValueType.AdjustValue(); + if (_data.TryGetValue(Column, out IValue Value)) + { + return Value; + } + return Column.ValueType.AdjustValue(); } /// @@ -59,19 +58,17 @@ private IValue TryValue(ValueTableColumn Column) [ContextMethod("Получить", "Get")] public IValue Get(int index) { - var C = Owner().Columns.FindColumnByIndex(index); - return TryValue(C); + return TryValue(_owner.Columns.FindColumnByIndex(index)); } public IValue Get(IValue index) { - var C = Owner().Columns.GetColumnByIIndex(index); - return TryValue(C); + return TryValue(_owner.Columns.GetColumnByIIndex(index)); } - public IValue Get(ValueTableColumn c) + public IValue Get(ValueTableColumn column) { - return TryValue(c); + return TryValue(column); } /// @@ -82,31 +79,29 @@ public IValue Get(ValueTableColumn c) [ContextMethod("Установить", "Set")] public void Set(int index, IValue value) { - var C = Owner().Columns.FindColumnByIndex(index); - Set(C, value); + Set(_owner.Columns.FindColumnByIndex(index), value); } public void Set(IValue index, IValue value) { - var C = Owner().Columns.GetColumnByIIndex(index); - Set(C, value); + Set(_owner.Columns.GetColumnByIIndex(index), value); } public void Set(ValueTableColumn column, IValue value) { - Owner().Indexes.ElementRemoved(this); + _owner.Indexes.ElementRemoved(this); _data[column] = column.ValueType.AdjustValue(value); - Owner().Indexes.ElementAdded(this); + _owner.Indexes.ElementAdded(this); } - public void OnOwnerColumnRemoval(IValue column) + public void OnOwnerColumnRemoval(ValueTableColumn column) { _data.Remove(column); } public IEnumerator GetEnumerator() { - foreach (var item in Owner().Columns) + foreach (var item in _owner.Columns) { yield return TryValue(item); } @@ -124,51 +119,41 @@ public override int GetPropCount() public override string GetPropName(int propNum) { - return Owner().Columns.GetPropName(propNum); + return _owner.Columns.GetPropName(propNum); } public override int GetPropertyNumber(string name) { - return Owner().Columns.GetPropertyNumber(name); + return _owner.Columns.GetPropertyNumber(name); } - public override bool IsPropReadable(int propNum) - { - return true; - } + public override bool IsPropReadable(int propNum) => true; - public override bool IsPropWritable(int propNum) - { - return true; - } + public override bool IsPropWritable(int propNum) => true; public override IValue GetPropValue(int propNum) { - var C = Owner().Columns.FindColumnByIndex(propNum); - return TryValue(C); + return TryValue(_owner.Columns.FindColumnByIndex(propNum)); } public override void SetPropValue(int propNum, IValue newVal) { - var C = Owner().Columns.FindColumnByIndex(propNum); - Set(C, newVal); + Set(_owner.Columns.FindColumnByIndex(propNum), newVal); } private ValueTableColumn GetColumnByIIndex(IValue index) { - return Owner().Columns.GetColumnByIIndex(index); + return _owner.Columns.GetColumnByIIndex(index); } public override IValue GetIndexedValue(IValue index) { - ValueTableColumn C = GetColumnByIIndex(index); - return TryValue(C); + return TryValue(GetColumnByIIndex(index)); } public override void SetIndexedValue(IValue index, IValue val) { - var C = GetColumnByIIndex(index); - _data[C] = C.ValueType.AdjustValue(val); + Set(GetColumnByIIndex(index), val); } void IDebugPresentationAcceptor.Accept(IDebugValueVisitor visitor) diff --git a/src/OneScript.StandardLibrary/Http/HttpResponseBody.cs b/src/OneScript.StandardLibrary/Http/HttpResponseBody.cs index 6a9eb8106..92e7dab39 100644 --- a/src/OneScript.StandardLibrary/Http/HttpResponseBody.cs +++ b/src/OneScript.StandardLibrary/Http/HttpResponseBody.cs @@ -1,4 +1,4 @@ -/*---------------------------------------------------------- +/*---------------------------------------------------------- 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 @@ -23,8 +23,10 @@ class HttpResponseBody : IDisposable bool _backFileIsTemp = false; byte[] _inMemBody; - private readonly bool _autoDecompress; + private readonly bool _autoDecompress; private long _contentSize = 0; + private readonly Stream _rawStream; + private bool _inMemoryResponseInited; public HttpResponseBody(HttpWebResponse response, string dumpToFile) { @@ -33,47 +35,60 @@ public HttpResponseBody(HttpWebResponse response, string dumpToFile) _inMemBody = Array.Empty(); return; } - + + _inMemoryResponseInited = false; + _rawStream = response.GetResponseStream(); _autoDecompress = string.Equals(response.ContentEncoding, "gzip", StringComparison.OrdinalIgnoreCase); _contentSize = _autoDecompress ? -1 : response.ContentLength; - if (String.IsNullOrEmpty(dumpToFile)) + if (!String.IsNullOrEmpty(dumpToFile)) { - InitInMemoryResponse(response); + InitFileBackedResponse(dumpToFile); } - else + else if(_autoDecompress) { - InitFileBackedResponse(response, dumpToFile); + InitInMemoryResponse(); } } - private void InitInMemoryResponse(HttpWebResponse response) + private void InitInMemoryResponse() { if(_contentSize > INMEMORY_BODY_LIMIT) { var filename = Path.GetTempFileName(); _backFileIsTemp = true; - InitFileBackedResponse(response, filename); + InitFileBackedResponse(filename); } else { if(_contentSize == UNDEFINED_LENGTH) { - ReadToStream(response); + ReadToStream(); } else { - ReadToArray(response); + ReadToArray(); } } + _inMemoryResponseInited = true; } public bool AutoDecompress => _autoDecompress; public long ContentSize => _contentSize < 0 ? 0 : _contentSize; - public Stream OpenReadStream() + public Stream OpenReadStream(bool raw = false) { + if (raw) + { + return GetResponseStream(); + } + + if (!_inMemoryResponseInited) + { + InitInMemoryResponse(); + } + if (_backingFileName != null) { return new FileStream(_backingFileName, FileMode.Open, FileAccess.Read); @@ -86,16 +101,16 @@ public Stream OpenReadStream() throw new InvalidOperationException("No response body"); } - private Stream GetResponseStream(HttpWebResponse response) + private Stream GetResponseStream() { if (_autoDecompress) - return new GZipStream(response.GetResponseStream(), CompressionMode.Decompress); - return response.GetResponseStream(); + return new GZipStream(_rawStream, CompressionMode.Decompress); + return _rawStream; } - - private void ReadToStream(HttpWebResponse response) + + private void ReadToStream() { - using (var responseStream = GetResponseStream(response)) + using (var responseStream = GetResponseStream()) using(var ms = new MemoryStream()) { bool memStreamIsAlive = true; @@ -117,7 +132,7 @@ private void ReadToStream(HttpWebResponse response) var filename = Path.GetTempFileName(); _backFileIsTemp = true; _backingFileName = filename; - + ms.Position = 0; using (var file = new FileStream(filename, FileMode.Create)) { @@ -144,11 +159,11 @@ private void ReadToStream(HttpWebResponse response) } } - private void ReadToArray(HttpWebResponse response) + private void ReadToArray() { System.Diagnostics.Debug.Assert(_contentSize <= INMEMORY_BODY_LIMIT); - - using var stream = GetResponseStream(response); + + using var stream = GetResponseStream(); var mustRead = (int)_contentSize; _inMemBody = new byte[mustRead]; int offset = 0; @@ -166,10 +181,10 @@ private void ReadToArray(HttpWebResponse response) } } - private void InitFileBackedResponse(HttpWebResponse response, string backingFileName) + private void InitFileBackedResponse(string backingFileName) { _backingFileName = backingFileName; - using(var responseStream = GetResponseStream(response)) + using (var responseStream = GetResponseStream()) { using(var file = new FileStream(backingFileName, FileMode.Create)) { @@ -193,7 +208,7 @@ private static void StreamToStreamCopy(Stream responseStream, Stream acceptor) private void Dispose(bool manualDispose) { - if(manualDispose) + if (manualDispose) { GC.SuppressFinalize(this); _inMemBody = null; diff --git a/src/OneScript.StandardLibrary/Http/HttpResponseContext.cs b/src/OneScript.StandardLibrary/Http/HttpResponseContext.cs index 6f4f0fcbb..247844387 100644 --- a/src/OneScript.StandardLibrary/Http/HttpResponseContext.cs +++ b/src/OneScript.StandardLibrary/Http/HttpResponseContext.cs @@ -1,4 +1,4 @@ -/*---------------------------------------------------------- +/*---------------------------------------------------------- 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 @@ -28,34 +28,24 @@ public class HttpResponseContext : AutoContext, IDisposable // TODO: Нельзя выделить массив размером больше чем 2GB // поэтому функционал сохранения в файл не должен использовать промежуточный буфер _body private HttpResponseBody _body; - + private HttpWebResponse _response; + private string _defaultCharset; private string _filename; - public HttpResponseContext(HttpWebResponse response) - { - RetrieveResponseData(response, null); - } - public HttpResponseContext(HttpWebResponse response, string dumpToFile) { - RetrieveResponseData(response, dumpToFile); - } + StatusCode = (int)response.StatusCode; + _defaultCharset = response.CharacterSet; - private void RetrieveResponseData(HttpWebResponse response, string dumpToFile) - { - using(response) + ProcessHeaders(response.Headers); + ProcessResponseBody(response, dumpToFile); + _response = response; + + if (_body != null && _body.AutoDecompress) { - StatusCode = (int)response.StatusCode; - _defaultCharset = response.CharacterSet; - - ProcessHeaders(response.Headers); - ProcessResponseBody(response, dumpToFile); - if (_body != null && _body.AutoDecompress) - { - _headers.Delete(ValueFactory.Create("Content-Encoding")); - _headers.SetIndexedValue(ValueFactory.Create("Content-Length"), ValueFactory.Create(_body.ContentSize)); - } + _headers.Delete(ValueFactory.Create("Content-Encoding")); + _headers.SetIndexedValue(ValueFactory.Create("Content-Length"), ValueFactory.Create(_body.ContentSize)); } } @@ -83,13 +73,7 @@ private void ProcessResponseBody(HttpWebResponse response, string dumpToFile) /// Соответствие. Заголовки ответа сервера. /// [ContextProperty("Заголовки", "Headers")] - public MapImpl Headers - { - get - { - return _headers; - } - } + public MapImpl Headers => _headers; /// /// Код состояния HTTP ответа. Число. @@ -137,24 +121,24 @@ public IValue GetBodyAsBinaryData() return ValueFactory.Create(); using (var stream = _body.OpenReadStream()) - { - var data = new byte[stream.Length]; - stream.Read(data, 0, data.Length); - return new BinaryDataContext(data); + using (var memoryStream = new MemoryStream()) + { + stream.CopyTo(memoryStream); + return new BinaryDataContext(memoryStream.ToArray()); } } /// /// Интерпретировать ответ, как Поток /// + /// Булево. Будет получен сырой поток без дополнительной обработки. По умолчанию Ложь /// Поток [ContextMethod("ПолучитьТелоКакПоток", "GetBodyAsStream")] - public IValue GetBodyAsStream() + public IValue GetBodyAsStream(bool rawStream = false) { if (_body == null) return ValueFactory.Create(); - - return new GenericStream(_body.OpenReadStream(), true); + return new GenericStream(_body.OpenReadStream(rawStream), true); } /// @@ -181,8 +165,11 @@ public void Close() public void Dispose() { - if (_body != null) - _body.Dispose(); + _response?.Dispose(); + _response = null; + + _body?.Dispose(); + _body = null; } } } diff --git a/src/OneScript.StandardLibrary/Reflector.cs b/src/OneScript.StandardLibrary/Reflector.cs index cde26d601..f36dd01e1 100644 --- a/src/OneScript.StandardLibrary/Reflector.cs +++ b/src/OneScript.StandardLibrary/Reflector.cs @@ -163,27 +163,41 @@ private static ValueTable CreateAnnotationTable(BslAnnotationAttribute[] annotat { annotationRow.Set(annotationNameColumn, ValueFactory.Create(annotation.Name)); } - var parametersTable = new ValueTable(); - var parameterNameColumn = parametersTable.Columns.Add("Имя"); - var parameterValueColumn = parametersTable.Columns.Add("Значение"); - + var parametersTable = FillAnnotationParameters(annotation.Parameters); annotationRow.Set(annotationParamsColumn, parametersTable); - if (annotation.Parameters.Any()) - { + } - foreach (var annotationParameter in annotation.Parameters) - { - var parameterRow = parametersTable.Add(); - if (annotationParameter.Name != null) - { - parameterRow.Set(parameterNameColumn, ValueFactory.Create(annotationParameter.Name)); - } - parameterRow.Set(parameterValueColumn, annotationParameter.Value); - } + return annotationsTable; + } + + private static ValueTable FillAnnotationParameters(IEnumerable parameters) + { + var parametersTable = new ValueTable(); + var parameterNameColumn = parametersTable.Columns.Add("Имя"); + var parameterValueColumn = parametersTable.Columns.Add("Значение"); + + foreach (var annotationParameter in parameters) + { + var parameterRow = parametersTable.Add(); + if (annotationParameter.Name != null) + { + parameterRow.Set(parameterNameColumn, ValueFactory.Create(annotationParameter.Name)); + } + if (annotationParameter.Value is BslAnnotationValue annotationValue) + { + var expandedValue = EmptyAnnotationsTable(); + var row = expandedValue.Add(); + row.Set(expandedValue.Columns.FindColumnByName("Имя"), ValueFactory.Create(annotationValue.Name)); + row.Set(expandedValue.Columns.FindColumnByName("Параметры"), FillAnnotationParameters(annotationValue.Parameters)); + parameterRow.Set(parameterValueColumn, row); + } + else + { + parameterRow.Set(parameterValueColumn, annotationParameter.Value); } } - return annotationsTable; + return parametersTable; } private static bool MethodExistsForType(BslTypeValue type, string methodName) diff --git a/src/ScriptEngine/Compiler/CompilerFrontend.cs b/src/ScriptEngine/Compiler/CompilerFrontend.cs index 8cd2b0489..2125cc694 100644 --- a/src/ScriptEngine/Compiler/CompilerFrontend.cs +++ b/src/ScriptEngine/Compiler/CompilerFrontend.cs @@ -59,7 +59,7 @@ private ICompilerBackend StackInitializer() } else { - actualBehavior = ExplicitImportsBehavior.Enabled; + actualBehavior = ExplicitImportsBehavior.Warn; } } diff --git a/src/ScriptEngine/Compiler/StackMachineCodeGenerator.cs b/src/ScriptEngine/Compiler/StackMachineCodeGenerator.cs index 8642b9a6d..e63ac5c0a 100644 --- a/src/ScriptEngine/Compiler/StackMachineCodeGenerator.cs +++ b/src/ScriptEngine/Compiler/StackMachineCodeGenerator.cs @@ -12,6 +12,7 @@ This Source Code Form is subject to the terms of the using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; +using System.Text; using OneScript.Compilation; using OneScript.Compilation.Binding; using OneScript.Contexts; @@ -1237,23 +1238,35 @@ private IEnumerable GetAnnotationParameters(AnnotationNo private BslAnnotationParameter MakeAnnotationParameter(AnnotationParameterNode param) { - BslAnnotationParameter result; + var runtimeValue = MakeAnnotationParameterValueConstant(param); + return new BslAnnotationParameter(param.Name, runtimeValue); + } + + private BslPrimitiveValue MakeAnnotationParameterValueConstant(AnnotationParameterNode param) + { + if (param.AnnotationNode != null) + { + var runtimeValue = new BslAnnotationValue(param.AnnotationNode.Name); + foreach (var child in param.AnnotationNode.Children) + { + var parameter = (AnnotationParameterNode)child; + var parameterValue = MakeAnnotationParameterValueConstant(parameter); + runtimeValue.Parameters.Add(new BslAnnotationParameter(parameter.Name, parameterValue)); + } + return runtimeValue; + } + else if (param.Value.Type != LexemType.NotALexem) { var constDef = CreateConstDefinition(param.Value); var constNumber = GetConstNumber(constDef); var runtimeValue = _module.Constants[constNumber]; - result = new BslAnnotationParameter(param.Name, runtimeValue) - { - ConstantValueIndex = constNumber - }; + return runtimeValue; } else { - result = new BslAnnotationParameter(param.Name, null); + return null; } - - return result; } private IEnumerable GetAnnotations(AnnotatableNode parent) @@ -1302,7 +1315,7 @@ private static ConstDefinition CreateConstDefinition(in Lexem lex) }; return cDef; } - + private int GetConstNumber(in ConstDefinition cDef) { var idx = _constMap.IndexOf(cDef); diff --git a/src/ScriptEngine/ExplicitImportsBehavior.cs b/src/ScriptEngine/ExplicitImportsBehavior.cs index 5811a6750..e2041643b 100644 --- a/src/ScriptEngine/ExplicitImportsBehavior.cs +++ b/src/ScriptEngine/ExplicitImportsBehavior.cs @@ -23,8 +23,8 @@ public enum ExplicitImportsBehavior Warn, /// - /// В режиме разработки (при наличии включенного отладчика) обращение к символу без явного импорта вызывает ошибку компиляции. - /// Без отладчика ошибки не происходит. + /// В режиме разработки (при наличии включенного отладчика) обращение к символу без явного импорта записывает предупреждение в лог. + /// Без отладчика проверка отключена. /// Development, diff --git a/src/ScriptEngine/Machine/AnnotationDefinition.cs b/src/ScriptEngine/Machine/AnnotationDefinition.cs new file mode 100644 index 000000000..4a8aa2634 --- /dev/null +++ b/src/ScriptEngine/Machine/AnnotationDefinition.cs @@ -0,0 +1,17 @@ +/*---------------------------------------------------------- +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; + +namespace ScriptEngine.Machine +{ + public struct AnnotationDefinition + { + public string Name; + public AnnotationParameter[] Parameters; + public readonly int ParamCount => Parameters?.Length ?? 0; + } +} diff --git a/src/ScriptEngine/Machine/AnnotationParameter.cs b/src/ScriptEngine/Machine/AnnotationParameter.cs new file mode 100644 index 000000000..2193df9d4 --- /dev/null +++ b/src/ScriptEngine/Machine/AnnotationParameter.cs @@ -0,0 +1,23 @@ +/*---------------------------------------------------------- +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 OneScript.Commons; + +namespace ScriptEngine.Machine +{ + public struct AnnotationParameter + { + public string Name; + + public IValue RuntimeValue; + + public override readonly string ToString() + { + return Utils.NameAndValuePresentation(Name, RuntimeValue); + } + + } +} diff --git a/src/ScriptEngine/Machine/Contexts/ContextValuesMarshaller.cs b/src/ScriptEngine/Machine/Contexts/ContextValuesMarshaller.cs index f64d2aeea..b6e5b9c7e 100644 --- a/src/ScriptEngine/Machine/Contexts/ContextValuesMarshaller.cs +++ b/src/ScriptEngine/Machine/Contexts/ContextValuesMarshaller.cs @@ -242,8 +242,11 @@ private static object ConvertValueType(IValue value, Type type, IBslProcess proc valueObj = value.AsBoolean(); } else if (typeof(IRuntimeContextInstance).IsAssignableFrom(type)) - { - valueObj = value.AsObject(); + { + if (value.GetType().IsAssignableTo(type)) + valueObj = value.AsObject(); + else + throw new InvalidCastException(); } else if (value is EnumerationValue && typeof(EnumerationValue).IsAssignableFrom(type)) { diff --git a/src/ScriptEngine/Machine/Contexts/StackTraceCollectionContext.cs b/src/ScriptEngine/Machine/Contexts/StackTraceCollectionContext.cs index 4599a6200..ec110be52 100644 --- a/src/ScriptEngine/Machine/Contexts/StackTraceCollectionContext.cs +++ b/src/ScriptEngine/Machine/Contexts/StackTraceCollectionContext.cs @@ -53,15 +53,9 @@ public override IValue GetIndexedValue(IValue index) var idx = (int)index.AsNumber(); if (idx < 0 || idx >= Count()) - throw IndexOutOfBoundsException(); + throw RuntimeException.IndexOutOfRange(); return _frames[idx]; } - - private static RuntimeException IndexOutOfBoundsException() - { - return new RuntimeException("Значение индекса выходит за пределы диапазона"); - } - } } diff --git a/src/ScriptEngine/Machine/Core.cs b/src/ScriptEngine/Machine/Core.cs index 0403ccffe..a80ebf919 100644 --- a/src/ScriptEngine/Machine/Core.cs +++ b/src/ScriptEngine/Machine/Core.cs @@ -181,38 +181,4 @@ public bool Equals(ConstDefinition other) } } - - [Serializable] - public struct AnnotationDefinition - { - public string Name; - public AnnotationParameter[] Parameters; - - public int ParamCount => Parameters?.Length ?? 0; - } - - [Serializable] - public struct AnnotationParameter - { - public string Name; - public int ValueIndex; - - [NonSerialized] - public IValue RuntimeValue; - - public const int UNDEFINED_VALUE_INDEX = -1; - - public override string ToString() - { - if (string.IsNullOrEmpty(Name)) - { - return string.Format("[{0}]", ValueIndex); - } - if (ValueIndex == UNDEFINED_VALUE_INDEX) - { - return Name; - } - return String.Format("{0}=[{1}]", Name, ValueIndex); - } - } } diff --git a/src/ScriptEngine/Machine/StackRuntimeAdoptionExtensions.cs b/src/ScriptEngine/Machine/StackRuntimeAdoptionExtensions.cs index d061c75e0..f8d09b83a 100644 --- a/src/ScriptEngine/Machine/StackRuntimeAdoptionExtensions.cs +++ b/src/ScriptEngine/Machine/StackRuntimeAdoptionExtensions.cs @@ -50,7 +50,6 @@ public static AnnotationParameter ToMachineDefinition(this BslAnnotationParamete return new AnnotationParameter { Name = parameter.Name, - ValueIndex = parameter.ConstantValueIndex, RuntimeValue = parameter.Value, }; } @@ -80,10 +79,7 @@ public static BslAnnotationAttribute MakeBslAttribute(this in AnnotationDefiniti if (annotation.ParamCount > 0) { attribute.SetParameters(annotation.Parameters.Select(p => - new BslAnnotationParameter(p.Name, (BslPrimitiveValue) p.RuntimeValue) - { - ConstantValueIndex = p.ValueIndex - })); + new BslAnnotationParameter(p.Name, (BslPrimitiveValue) p.RuntimeValue))); } return attribute; diff --git a/src/Tests/OneScript.Core.Tests/CodeGenerationTests.cs b/src/Tests/OneScript.Core.Tests/CodeGenerationTests.cs index db8ec91c2..c95a796d4 100644 --- a/src/Tests/OneScript.Core.Tests/CodeGenerationTests.cs +++ b/src/Tests/OneScript.Core.Tests/CodeGenerationTests.cs @@ -15,8 +15,10 @@ This Source Code Form is subject to the terms of the using OneScript.Language.SyntaxAnalysis.AstNodes; using OneScript.Sources; using ScriptEngine; +using OneScript.Values; using ScriptEngine.Compiler; using ScriptEngine.Machine; +using System.Linq; using Xunit; namespace OneScript.Core.Tests @@ -54,6 +56,36 @@ public void Variables_Are_Registered_In_Image() var image = BuildModule(code, Mock.Of()); image.Fields.Should().HaveCount(2); } + + [Fact] + public void AnnotationsAsValuesInCode() { + var code = @" + &Аннотация(Параметр = &ТожеАннотация(&СТожеПараметромАннотацией, П2 = &СТожеПараметромАннотацией)) + Процедура Процедура1() Экспорт + КонецПроцедуры"; + var image = BuildModule(code, Mock.Of()); + image.Should().NotBeNull(); + image.Constants.Should().HaveCount(0); + image.Methods.Should().HaveCount(1); + image.Fields.Should().BeEmpty(); + + var method = image.Methods[0]; + method.GetAnnotations().Should().HaveCount(1); + + var annotation = method.GetAnnotations()[0]; + annotation.Parameters.Should().HaveCount(1); + + var annotationParameter = annotation.Parameters.First(); + annotationParameter.Value.Should().NotBeNull(); + annotationParameter.Value.Should().BeOfType(); + + var parameterValue = (BslAnnotationValue)annotationParameter.Value; + parameterValue.Parameters.Should().HaveCount(2); + parameterValue.Parameters.ElementAt(0).Value.Should().BeOfType(); + parameterValue.Parameters.ElementAt(1).Name.Should().Be("П2"); + parameterValue.Parameters.ElementAt(1).Value.Should().BeOfType(); + } + private static StackRuntimeModule BuildModule(string code, IBslProcess process) { diff --git a/src/Tests/OneScript.Core.Tests/ExplicitImportsTest.cs b/src/Tests/OneScript.Core.Tests/ExplicitImportsTest.cs index 040ff768f..1e6b79482 100644 --- a/src/Tests/OneScript.Core.Tests/ExplicitImportsTest.cs +++ b/src/Tests/OneScript.Core.Tests/ExplicitImportsTest.cs @@ -82,19 +82,26 @@ public void ExplicitImports_Warn_HasWarning() } [Fact] - public void ExplicitImports_Development_WithDebugger_CompilationError() + public void ExplicitImports_Development_WithDebugger_HasWarning() { + var debugSessionMock = new Mock(); + debugSessionMock.Setup(x => x.IsActive).Returns(false); + var debuggerMock = new Mock(); debuggerMock.Setup(x => x.IsEnabled).Returns(true); + debuggerMock.Setup(x => x.GetSession()).Returns(debugSessionMock.Object); - Action act = () => CompileClientScript( + var code = CompileClientScript( ExplicitImportsBehavior.Development, - out _, + out var shouldCompile, debuggerMock.Object); - act.Should().Throw() - .WithMessage("*" + LibraryModuleName + " принадлежит пакету " + LibraryShortName + "*", - "в режиме Development с включенным отладчиком должна быть ошибка"); + shouldCompile.Should().BeTrue(); + _messages.Should().HaveCount(1, "должно быть одно предупреждение") + .And.Contain(x => + x.Contains(LibraryModuleName, StringComparison.InvariantCultureIgnoreCase) && + x.Contains(LibraryShortName, StringComparison.InvariantCultureIgnoreCase), + "в режиме Development с включенным отладчиком должно быть предупреждение"); } [Fact] diff --git a/src/Tests/OneScript.DebugProtocol.Test/OneScript.DebugProtocol.Test.csproj b/src/Tests/OneScript.DebugProtocol.Test/OneScript.DebugProtocol.Test.csproj index bfb36c98c..120023d49 100644 --- a/src/Tests/OneScript.DebugProtocol.Test/OneScript.DebugProtocol.Test.csproj +++ b/src/Tests/OneScript.DebugProtocol.Test/OneScript.DebugProtocol.Test.csproj @@ -8,6 +8,7 @@ Debug;Release;LinuxDebug AnyCPU + true @@ -32,8 +33,5 @@ - - - diff --git a/src/Tests/VSCode.DebugAdapter.Tests/ReconcileForOlderVersionTests.cs b/src/Tests/OneScript.DebugProtocol.Test/ReconcileForOlderVersionTests.cs similarity index 96% rename from src/Tests/VSCode.DebugAdapter.Tests/ReconcileForOlderVersionTests.cs rename to src/Tests/OneScript.DebugProtocol.Test/ReconcileForOlderVersionTests.cs index 99236d778..af3a8d95b 100644 --- a/src/Tests/VSCode.DebugAdapter.Tests/ReconcileForOlderVersionTests.cs +++ b/src/Tests/OneScript.DebugProtocol.Test/ReconcileForOlderVersionTests.cs @@ -1,4 +1,4 @@ -/*---------------------------------------------------------- +/*---------------------------------------------------------- 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 @@ -13,7 +13,7 @@ This Source Code Form is subject to the terms of the using OneScript.DebugProtocol.TcpServer; using Xunit; -namespace VSCode.DebugAdapter.Tests +namespace OneScript.DebugProtocol.Test { public class ReconcileForOlderVersionTests { @@ -75,3 +75,4 @@ public void ExchangeReconcileVersions() } } } + diff --git a/src/Tests/OneScript.Language.Tests/ParserTests.cs b/src/Tests/OneScript.Language.Tests/ParserTests.cs index df02a0f01..23fef46f2 100644 --- a/src/Tests/OneScript.Language.Tests/ParserTests.cs +++ b/src/Tests/OneScript.Language.Tests/ParserTests.cs @@ -144,6 +144,30 @@ public void Check_Annotation_Parameters() } + [Fact] + public void CheckBuild_Of_AnnotationAsValue() + { + var code = @" + &Аннотация(Параметр = &ТожеАннотация(&СТожеПараметромАннотацией, П2 = &СТожеПараметромАннотацией)) + Процедура Процедура1() Экспорт + КонецПроцедуры"; + + var treeValidator = ParseModuleAndGetValidator(code); + + treeValidator.Is(NodeKind.MethodsSection); + + var methodNode = treeValidator.NextChild(); + methodNode.Is(NodeKind.Method); + var annotationNode = methodNode.NextChild(); + annotationNode.Is(NodeKind.Annotation); + var annotationParameter = annotationNode.NextChild(); + annotationParameter.Is(NodeKind.AnnotationParameter); + + annotationParameter + .NextChildIs(NodeKind.AnnotationParameterName) + .NextChildIs(NodeKind.Annotation); + } + [Fact] public void Check_Method_Parameters() { diff --git a/src/Tests/VSCode.DebugAdapter.Tests/VSCode.DebugAdapter.Tests.csproj b/src/Tests/VSCode.DebugAdapter.Tests/VSCode.DebugAdapter.Tests.csproj deleted file mode 100644 index da0cc0ce0..000000000 --- a/src/Tests/VSCode.DebugAdapter.Tests/VSCode.DebugAdapter.Tests.csproj +++ /dev/null @@ -1,23 +0,0 @@ - - - - net48 - Debug;Release;LinuxDebug - AnyCPU - 7.3 - true - - - - - - - - - - - - - - - diff --git a/src/VSCode.DebugAdapter/package.json b/src/VSCode.DebugAdapter/package.json index 041520a14..931c390c5 100644 --- a/src/VSCode.DebugAdapter/package.json +++ b/src/VSCode.DebugAdapter/package.json @@ -1,7 +1,7 @@ { "name": "oscript-debug", "displayName": "OneScript Debug (BSL)", - "version": "0.10.0", + "version": "1.0.0", "publisher": "EvilBeaver", "description": "Visual Studio Code debugger extension for OneScript (BSL)", "icon": "images/logo-dbg.png", diff --git a/tests/ValueTableIndex.os b/tests/ValueTableIndex.os index b1a0e1b45..8305f5862 100644 --- a/tests/ValueTableIndex.os +++ b/tests/ValueTableIndex.os @@ -24,6 +24,7 @@ ВсеТесты.Добавить("ТестДолжен_ПроверитьПоискСИндексом"); ВсеТесты.Добавить("ТестДолжен_ПоведениеИндексовПриУдаленииКолонок"); ВсеТесты.Добавить("ТестДолжен_ПоведениеИндексовПриИзмененииЗначенийИндексированныхПолей"); + ВсеТесты.Добавить("ТестДолжен_ПоведениеИндексовПриИзмененииЗначенийИндексированныхПолейПоИндексу"); ВсеТесты.Добавить("ТестДолжен_ПроверитьВыбросИсключений"); ВсеТесты.Добавить("ТестДолжен_ПроверитьПоискПоИндексированнойКолонкеСЗаданнымТипом"); @@ -179,6 +180,29 @@ КонецПроцедуры +Процедура ТестДолжен_ПоведениеИндексовПриИзмененииЗначенийИндексированныхПолейПоИндексу() Экспорт + + Т = Новый ТаблицаЗначений; + Т.Колонки.Добавить("К1"); + Т.Колонки.Добавить("К2"); + Т.Индексы.Добавить("К2"); + Т.Индексы.Добавить("К2, К1"); + Т.Индексы.Добавить("К1"); + Т.Добавить().К1 = 1; + Т.Добавить().К1 = 2; + Т.Добавить().К1 = 3; + + Т[0]["К1"] = 3; + Т[1]["К1"] = 2; + Т[2]["К1"] = 1; + + СтруктураПоиска = Новый Структура("К1", 1); + НайденныеСтроки = Т.НайтиСтроки(СтруктураПоиска); + юТест.ПроверитьРавенство(НайденныеСтроки.Количество(), 1); + юТест.ПроверитьРавенство(НайденныеСтроки[0], Т[2]); + +КонецПроцедуры + Процедура ТестДолжен_ПроверитьВыбросИсключений() Экспорт Т = Новый ТаблицаЗначений; diff --git a/tests/annotations.os b/tests/annotations.os index 7fef57889..a095cf5c5 100644 --- a/tests/annotations.os +++ b/tests/annotations.os @@ -14,10 +14,37 @@ ВсеТесты.Добавить("ТестДолжен_ПроверитьАннотацииПолейЗагрузитьСценарий"); ВсеТесты.Добавить("ТестДолжен_ПроверитьАннотацииПолейЗагрузитьСценарийИзСтроки"); + ВсеТесты.Добавить("ТестДолжен_ПроверитьАннотациюКакЗначениеПараметраАннотации"); + Возврат ВсеТесты; КонецФункции +&Аннотация(Параметр = &ТожеАннотация(&СТожеПараметромАннотацией, П2 = &СТожеПараметромАннотацией)) +Процедура ТестДолжен_ПроверитьАннотациюКакЗначениеПараметраАннотации() Экспорт + + Рефлектор = Новый Рефлектор; + ТаблицаМетодов = Рефлектор.ПолучитьТаблицуМетодов(ЭтотОбъект); + + юТест.ПроверитьНеРавенство(ТаблицаМетодов.Колонки.Найти("Аннотации"), Неопределено, "Есть колонка Аннотации"); + + СтрокаМетода = ТаблицаМетодов.Найти("ТестДолжен_ПроверитьАннотациюКакЗначениеПараметраАннотации", "Имя"); + ПерваяАннотация = СтрокаМетода.Аннотации[0]; + ПервыйПараметрПервойАннотации = ПерваяАннотация.Параметры[0]; + + юТест.ПроверитьТип(ПервыйПараметрПервойАннотации.Значение, Тип("СтрокаТаблицыЗначений")); + + юТест.ПроверитьРавенство(ПервыйПараметрПервойАннотации.Значение.Имя, "ТожеАннотация"); + юТест.ПроверитьТип(ПервыйПараметрПервойАннотации.Значение.Параметры, Тип("ТаблицаЗначений")); + + юТест.ПроверитьТип(ПервыйПараметрПервойАннотации.Значение.Параметры[0].Значение, Тип("СтрокаТаблицыЗначений")); + юТест.ПроверитьРавенство(ПервыйПараметрПервойАннотации.Значение.Параметры[0].Значение.Имя, "СТожеПараметромАннотацией"); + + юТест.ПроверитьРавенство(ПервыйПараметрПервойАннотации.Значение.Параметры[1].Имя, "П2"); + юТест.ПроверитьРавенство(ПервыйПараметрПервойАннотации.Значение.Параметры[1].Значение.Имя, "СТожеПараметромАннотацией"); + +КонецПроцедуры + Процедура САннотированнымиПараметрами( &АннотацияДляПараметра @@ -197,4 +224,4 @@ КонецЕсли; -КонецПроцедуры \ No newline at end of file +КонецПроцедуры diff --git a/tests/binary-objects.os b/tests/binary-objects.os index 25d7c04c9..631c39f21 100644 --- a/tests/binary-objects.os +++ b/tests/binary-objects.os @@ -277,7 +277,7 @@ Буфер = ПолучитьБуферДвоичныхДанныхИзHexСтроки("01 02 03"); Буфер.ЗаписатьПобитовоеИсключительноеИли(-1, ВторойБуфер, 3); Исключение - юТест.ПроверитьВхождение(ОписаниеОшибки(), "Значение индекса выходит за границы диапазона"); + юТест.ПроверитьВхождение(ОписаниеОшибки(), "Значение индекса выходит за пределы диапазона"); КонецПопытки; КонецПроцедуры diff --git a/tests/global-funcs.os b/tests/global-funcs.os index dc9ddf03f..159433ae9 100644 --- a/tests/global-funcs.os +++ b/tests/global-funcs.os @@ -6,12 +6,18 @@ /////////////////////////////////////////////////////////////////////// Перем юТест; +Перем мАдресРесурса; // URL ресурса (хоста) для тестирования запросов //////////////////////////////////////////////////////////////////// // Программный интерфейс Функция ПолучитьСписокТестов(ЮнитТестирование) Экспорт + Если мАдресРесурса = Неопределено Тогда + ПодключитьСценарий("./tests/http.os", "http_тест"); + мАдресРесурса = Новый http_тест().ВыбратьДоступныйХост(); + КонецЕсли; + юТест = ЮнитТестирование; ВсеТесты = Новый Массив; @@ -652,7 +658,7 @@ Приемник = ПолучитьИмяВременногоФайла(); - КопироватьФайл("http://httpbin.org/image", Приемник); + КопироватьФайл(мАдресРесурса + "/image", Приемник); Попытка ДД = Новый ДвоичныеДанные(Приемник); @@ -670,7 +676,7 @@ Приемник = ПолучитьИмяВременногоФайла(); - КопироватьФайл("https://httpbin.org/image", Приемник); + КопироватьФайл(мАдресРесурса + "/image", Приемник); Попытка ДД = Новый ДвоичныеДанные(Приемник); @@ -689,7 +695,7 @@ Приемник = ПолучитьИмяВременногоФайла(); Попытка - ПереместитьФайл("http://httpbin.org/image", Приемник); + ПереместитьФайл(мАдресРесурса + "/image", Приемник); Исключение //Отвалится по 405, значит delete метод отрабатывает Описание = ОписаниеОшибки(); diff --git a/tests/http.os b/tests/http.os index d2f89a6d5..9e6fb44ee 100644 --- a/tests/http.os +++ b/tests/http.os @@ -1,6 +1,7 @@ Перем юТест; Перем мАдресРесурса; // URL ресурса (хоста) для тестирования запросов +Перем ПортТестовогоСервера; Функция ПолучитьСписокТестов(ЮнитТестирование) Экспорт @@ -36,6 +37,13 @@ ВсеТесты.Добавить("ТестДолженПроверитьЧтоМожноЗадатьТелоЗапросаСПомощьюПотока"); ВсеТесты.Добавить("ТестДолженПроверитьЧтоМетодыБезТелаПриУстановленномТелеУспешноВыполняются"); + ВсеТесты.Добавить("ТестДолженПроверитьЧтоРаботаетПолучениеДвоичныхДанныхИзОтвета"); + + ВсеТесты.Добавить("ТестДолженПроверитьЧтоТелоМожноПолучитьНесколькоРаз"); + ВсеТесты.Добавить("ТестДолженПроверитьПолучениеТелаПослеЗакрытогоПотока"); + ВсеТесты.Добавить("ТестДолженПроверитьНедоступностьЧистогоПотокаПослеПолученияТела"); + + ВсеТесты.Добавить("ТестДолженПроверитьПолучениеStreamEvent"); Возврат ВсеТесты; КонецФункции @@ -376,6 +384,157 @@ КонецПроцедуры +Процедура ТестДолженПроверитьЧтоРаботаетПолучениеДвоичныхДанныхИзОтвета() Экспорт + + Запрос = Новый HttpЗапрос("/bytes/10"); + Соединение = Новый HttpСоединение(мАдресРесурса); + Ответ = Соединение.ВызватьHTTPМетод("GET", Запрос); + + ДД = Ответ.ПолучитьТелоКакДвоичныеДанные(); + юТест.ПроверитьТип(ДД, Тип("ДвоичныеДанные")); + юТест.ПроверитьРавенство(ДД.Размер(), 10); + +КонецПроцедуры + + Процедура ТестДолженПроверитьЧтоТелоМожноПолучитьНесколькоРаз() Экспорт + + Запрос = Новый HttpЗапрос("/get?p1=v1&p2=v2"); + + Соединение = Новый HttpСоединение(мАдресРесурса); + Ответ = Соединение.Получить(Запрос); + + юТест.ПроверитьРавенство(200, Ответ.КодСостояния); + + Ответ.ПолучитьТелоКакПоток(); + + юТест.ПроверитьРавенство(Ответ.ПолучитьТелоКакПоток().ДоступноЧтение, Истина); + + юТест.ПроверитьРавенство(ТипЗнч(Ответ.ПолучитьТелоКакДвоичныеДанные()), Тип("ДвоичныеДанные")); + юТест.ПроверитьВхождение(Ответ.ПолучитьТелоКакСтроку(), """p1"": ""v1"""); + юТест.ПроверитьВхождение(Ответ.ПолучитьТелоКакСтроку(), """p2"": ""v2"""); + + юТест.ПроверитьРавенство(ТипЗнч(Ответ.ПолучитьТелоКакДвоичныеДанные()), Тип("ДвоичныеДанные")); + + // Оригинальный поток уже вычитан вернется поддельный + юТест.ПроверитьРавенство(Ответ.ПолучитьТелоКакПоток().ДоступноЧтение, Истина); + +КонецПроцедуры + +Процедура ТестДолженПроверитьПолучениеТелаПослеЗакрытогоПотока() Экспорт + + Запрос = Новый HttpЗапрос("/get?p1=v1&p2=v2"); + + Соединение = Новый HttpСоединение(мАдресРесурса); + Ответ = Соединение.Получить(Запрос); + + юТест.ПроверитьРавенство(200, Ответ.КодСостояния); + + Поток = Ответ.ПолучитьТелоКакПоток(); + Поток.Закрыть(); + + юТест.ПроверитьВхождение(Ответ.ПолучитьТелоКакСтроку(), """p2"": ""v2"""); + +КонецПроцедуры + +Процедура ТестДолженПроверитьНедоступностьЧистогоПотокаПослеПолученияТела() Экспорт + + Запрос = Новый HttpЗапрос("/get?p1=v1&p2=v2"); + + Соединение = Новый HttpСоединение(мАдресРесурса); + Ответ = Соединение.Получить(Запрос); + + юТест.ПроверитьРавенство(200, Ответ.КодСостояния); + + юТест.ПроверитьВхождение(Ответ.ПолучитьТелоКакСтроку(), """p2"": ""v2"""); + + // чистый поток не доступен для чтения + Поток = Ответ.ПолучитьТелоКакПоток(Истина); + юТест.ПроверитьРавенство(Поток.ДоступноЧтение, Ложь); + + // оберточный нормальный + Поток = Ответ.ПолучитьТелоКакПоток(); + юТест.ПроверитьРавенство(Поток.ДоступноЧтение, Истина); + ЧтениеДанных = Новый ЧтениеДанных(Поток); + юТест.ПроверитьВхождение( + ПолучитьСтрокуИзДвоичныхДанных(ЧтениеДанных.Прочитать().ПолучитьДвоичныеДанные()), + """p2"": ""v2""" + ); + +КонецПроцедуры + +Процедура ТестДолженПроверитьПолучениеStreamEvent() Экспорт + + МенеджерФоновыхЗаданий = Новый МенеджерФоновыхЗаданий; + ЗаданиеВебсервера = МенеджерФоновыхЗаданий.Выполнить(ЭтотОбъект, "Вебсервер"); + + ПортТестовогоСервера = 8181; + Соединение = Новый HTTPСоединение("http://127.0.0.1:" + ПортТестовогоСервера); + Запрос = Новый HTTPЗапрос("/"); + + // Подождем пока поднимится сервер + Приостановить(1000); + + Старт = ТекущаяУниверсальнаяДатаВМиллисекундах(); + + Ответ = Соединение.ВызватьHTTPМетод("GET", Запрос); + + Прошло = ТекущаяУниверсальнаяДатаВМиллисекундах() - Старт; + ютест.ПроверитьМеньше(Прошло, 600); + + ТелоПоток = Ответ.ПолучитьТелоКакПоток(Истина); + юТест.ПроверитьТип(ТелоПоток, Тип("Поток")); + + ЧтениеДанных = Новый ЧтениеДанных(ТелоПоток); + Таймаут = 600; + Пока Истина Цикл + + ПрочтенныеДанные = ЧтениеДанных.Прочитать(20); + + Строка = ПолучитьСтрокуИзДвоичныхДанных(ПрочтенныеДанные.ПолучитьДвоичныеДанные()); + Прошло = ТекущаяУниверсальнаяДатаВМиллисекундах() - Старт; + + ютест.ПроверитьМеньше(Прошло, Таймаут); + + Таймаут = Таймаут + Таймаут; + Если Строка = "" ИЛИ Строка = "data: [DONE]" + Символы.ПС + Символы.ПС Тогда + Прервать; + КонецЕсли; + + юТест.ПроверитьРавенство(Строка, "data: [1]" + Символы.ПС + Символы.ПС); + + КонецЦикла; + + ТелоПоток.Закрыть(); + + МенеджерФоновыхЗаданий.Очистить(); +КонецПроцедуры + +Функция ОбработчикЗапроса(Контекст, СледующийОбработчик) Экспорт + + Контекст.Ответ.КодСостояния = 200; + Контекст.Ответ.ТипКонтента = "text/event-stream"; + + ПотокОтвета = ПолучитьДвоичныеДанныеИзСтроки("data: [1]" + Символы.ПС + Символы.ПС).ОткрытьПотокДляЧтения(); + ПотокОтвета.КопироватьВ(Контекст.Ответ.Тело); + + Приостановить(500); + ПотокОтвета = ПолучитьДвоичныеДанныеИзСтроки("data: [1]" + Символы.ПС + Символы.ПС).ОткрытьПотокДляЧтения(); + ПотокОтвета.КопироватьВ(Контекст.Ответ.Тело); + + Приостановить(500); + ПотокОтвета = ПолучитьДвоичныеДанныеИзСтроки("data: [DONE]" + Символы.ПС + Символы.ПС).ОткрытьПотокДляЧтения(); + ПотокОтвета.КопироватьВ(Контекст.Ответ.Тело); + +КонецФункции + +Процедура Вебсервер() Экспорт + + Вебсервер = Новый ВебСервер(ПортТестовогоСервера); + Вебсервер.ДобавитьОбработчикЗапросов(ЭтотОбъект, "ОбработчикЗапроса"); + Вебсервер.Запустить(); + +КонецПроцедуры + Функция JsonВОбъект(Json) ЧтениеJSON = Новый ЧтениеJSON; @@ -403,7 +562,7 @@ КонецФункции -Функция ВыбратьДоступныйХост() +Функция ВыбратьДоступныйХост() Экспорт // Если задана переменная окружения, используем ее при наличии значения ЗначениеИзОкружения = ПолучитьПеременнуюСреды("OS_HTTP_TEST_HOST"); @@ -418,6 +577,8 @@ // Пробуем типовые варианты httpbin Кандидаты = Новый Массив; + Кандидаты.Добавить("http://127.0.0.1:8085"); + Кандидаты.Добавить("https://connectorhttp.ru"); Кандидаты.Добавить("https://httpbin.org"); Кандидаты.Добавить("https://httpbingo.org"); diff --git a/tests/valuetable.os b/tests/valuetable.os index d02bb4653..3dcf51b80 100644 --- a/tests/valuetable.os +++ b/tests/valuetable.os @@ -30,7 +30,9 @@ ВсеТесты.Добавить("ТестДолжен_НайтиНесколькоСтрокВТаблице"); ВсеТесты.Добавить("ТестДолжен_СкопироватьТаблицуПолностью"); ВсеТесты.Добавить("ТестДолжен_СкопироватьТаблицуПоМассивуСтрок"); + ВсеТесты.Добавить("ТестДолжен_ПроверитьИсключениеПриКопированииТаблицыПоМассивуСтрок"); ВсеТесты.Добавить("ТестДолжен_СкопироватьТаблицуНесколькоКолонок"); + ВсеТесты.Добавить("ТестДолжен_СкопироватьТаблицуПоОтбору"); ВсеТесты.Добавить("ТестДолжен_ПроверитьСверткуБезУказанияКолонок"); ВсеТесты.Добавить("ТестДолжен_ЗагрузитьКолонку"); @@ -52,6 +54,38 @@ ВсеТесты.Добавить("ТестДолжен_ПроверитьСортировкуНеупорядочиваемыхТипов"); ВсеТесты.Добавить("ТестДолжен_ПроверитьСортировкуРазныхТипов"); ВсеТесты.Добавить("ТестДолжен_ПроверитьСортировкуПоПредставлению"); + + ВсеТесты.Добавить("ТестДолжен_ПроверитьВставкуВнеРазмераТаблицы"); + ВсеТесты.Добавить("ТестДолжен_ПроверитьИсключениеПриЗагрузкеКолонки"); + ВсеТесты.Добавить("ТестДолжен_ПроверитьИсключениеПриНеверномПараметреСортировки"); + ВсеТесты.Добавить("ТестДолжен_ПроверитьСортировкуСЛишнимиПробеламиВПараметрах"); + + ВсеТесты.Добавить("ТестДолжен_Проверить_ЗаполнитьЗначения_СПустымСпискомКолонок"); + ВсеТесты.Добавить("ТестДолжен_Проверить_Найти_СПустымСпискомКолонок"); + ВсеТесты.Добавить("ТестДолжен_Проверить_СкопироватьКолонки_СПустымСпискомКолонок"); + ВсеТесты.Добавить("ТестДолжен_Проверить_Скопировать_СПустымСпискомКолонок"); + + ВсеТесты.Добавить("ТестДолжен_ПроверитьИтогПоКолонкеСОписаниемТипов_Строка"); + ВсеТесты.Добавить("ТестДолжен_ПроверитьИтогПоКолонкеСОписаниемТипов_СтрокаЧисло"); + ВсеТесты.Добавить("ТестДолжен_ПроверитьИтогПоКолонкеСОписаниемТипов_СтрокаДата"); + ВсеТесты.Добавить("ТестДолжен_ПроверитьИтогПоКолонкеСОписаниемТипов_СтрокаБезЧисел"); + ВсеТесты.Добавить("ТестДолжен_ПроверитьИтогПоКолонкеСОписаниемТипов_СтрокаЧислоБезЧисел"); + ВсеТесты.Добавить("ТестДолжен_ПроверитьИтогПоКолонкеСОписаниемТипов_СтрокаДатаБезЧисел"); + ВсеТесты.Добавить("ТестДолжен_ПроверитьИтогПоКолонкеБезОписанияТипов_БезЧисел"); + + ВсеТесты.Добавить("ТестДолжен_ПроверитьИсключениеПриНеверномИмениКолонкиВОтборе"); + ВсеТесты.Добавить("ТестДолжен_ПроверитьЗапятуюВИменахКолонок_БезПустых"); + ВсеТесты.Добавить("ТестДолжен_ПроверитьЗапятуюВИменахКолонок_СПустыми"); + ВсеТесты.Добавить("ТестДолжен_ПроверитьИсключениеДляИндекса"); + + ВсеТесты.Добавить("ТестДолжен_ВызватьИсключениеПриДобавленииКолонкиСНевернымИменем"); + ВсеТесты.Добавить("ТестДолжен_ВызватьИсключениеПриВставкеКолонкиСНевернымИменем"); + ВсеТесты.Добавить("ТестДолжен_ВызватьИсключениеНаПоискеИндексаКолонкиСНевернымПримитивнымТипом"); + ВсеТесты.Добавить("ТестДолжен_ВызватьИсключениеНаПоискеИндексаКолонкиСНевернымОбъектнымТипом"); + + ВсеТесты.Добавить("ТестДолжен_ПроверитьИсключениеПолученияКолонкиСНевернымНомером"); + + Возврат ВсеТесты; КонецФункции @@ -267,7 +301,7 @@ Исключение Ошибка = ИнформацияОбОшибке().Описание; КонецПопытки; - юТест.ПроверитьРавенство(Ошибка, "Неверное значение аргумента номер 2"); + юТест.ПроверитьРавенство(Ошибка, "Неправильное смещение внутри коллекции"); Ошибка = "Сдвиг за пределы вверх"; Попытка @@ -275,7 +309,7 @@ Исключение Ошибка = ИнформацияОбОшибке().Описание; КонецПопытки; - юТест.ПроверитьРавенство(Ошибка, "Неверное значение аргумента номер 2"); + юТест.ПроверитьРавенство(Ошибка, "Неправильное смещение внутри коллекции"); Ошибка = "Сдвиг с неверным индексом"; Попытка @@ -527,6 +561,44 @@ КонецПроцедуры +Процедура ТестДолжен_СкопироватьТаблицуПоОтбору() Экспорт + + Т = СоздатьТаблицуСДанными(); + Т.Добавить().Значение = 4; + + Отбор = Новый Структура("Значение", 4); + Т2 = Т.Скопировать(Отбор,"Ключ"); + + юТест.ПроверитьНеравенство(Т, Т2); + юТест.ПроверитьРавенство(2, Т2.Количество()); + юТест.ПроверитьРавенство(1, Т2.Колонки.Количество()); + юТест.ПроверитьРавенство("Ключ4", Т2[0].Ключ); + юТест.ПроверитьРавенство(Неопределено, Т2[1].Ключ); + +КонецПроцедуры + +Процедура ТестДолжен_ПроверитьИсключениеПриКопированииТаблицыПоМассивуСтрок() Экспорт + + Т = СоздатьТаблицуСДанными(); + + Т0 = Новый ТаблицаЗначений(); + Т0.Колонки.Добавить("Тест"); + Т0.Добавить().Тест = 1; + + МассивСтрок = Новый Массив; + МассивСтрок.Добавить(Т0[0]); + + Попытка + Т2 = Т.Скопировать(МассивСтрок); + Исключение + Возврат; + КонецПопытки; + + ВызватьИсключение "Ожидали исключение, но его не было"; + +КонецПроцедуры + + Процедура ТестДолжен_ПроверитьСверткуБезУказанияКолонок() Экспорт Перем Т; @@ -951,3 +1023,297 @@ юТест.ПроверитьРавенство(КодСимвола(ТЗ[3].Тест,1), 917, "greek"); юТест.ПроверитьРавенство(КодСимвола(ТЗ[4].Тест,1), 1045, "cyrillic"); КонецПроцедуры + +Процедура ТестДолжен_ПроверитьВставкуВнеРазмераТаблицы() Экспорт + ТЗ = Новый ТаблицаЗначений(); + ТЗ.Колонки.Добавить("Тест"); + + ТЗ.Добавить().Тест = -1; + ТЗ.Вставить(8).Тест = -2; + + юТест.ПроверитьРавенство(ТЗ[1].Тест, -2); + +КонецПроцедуры + +Процедура ТестДолжен_ПроверитьИсключениеПриЗагрузкеКолонки() Экспорт + ТЗ = Новый ТаблицаЗначений(); + ТЗ.Колонки.Добавить("Тест"); + + Попытка + ТЗ.ЗагрузитьКолонку(8,"Тест"); + Исключение + юТест.ПроверитьРавенство(Найти(ИнформацияОбОшибке().Описание,"NullReferenceException"), 0, "NRE"); + Возврат; + КонецПопытки; + + ВызватьИсключение "Ожидали исключение, но его не было"; +КонецПроцедуры + +Процедура ТестДолжен_ПроверитьИсключениеПриНеверномПараметреСортировки() Экспорт + ТЗ = Новый ТаблицаЗначений(); + ТЗ.Колонки.Добавить("Тест"); + ТЗ.Добавить().Тест = 1; + ТЗ.Добавить().Тест = 2; + + Попытка + ТЗ.Сортировать("Тест УБЫВ и_лишнее_через_пробел"); + Исключение + Возврат; + КонецПопытки; + + ВызватьИсключение "Ожидали исключение, но его не было"; +КонецПроцедуры + + +Процедура ТестДолжен_ПроверитьСортировкуСЛишнимиПробеламиВПараметрах() Экспорт + ТЗ = Новый ТаблицаЗначений(); + ТЗ.Колонки.Добавить("Тест"); + ТЗ.Колонки.Добавить("Тест2"); + ТЗ.Добавить().Тест = 1; + ТЗ.Добавить().Тест2 = 2; + + ТЗ.Сортировать(" Тест УБЫВ , Тест2 ВОЗР "); +КонецПроцедуры + + +Процедура ТестДолжен_Проверить_ЗаполнитьЗначения_СПустымСпискомКолонок() Экспорт + ТЗ = Новый ТаблицаЗначений(); + ТЗ.Колонки.Добавить("Тест"); + ТЗ.Добавить().Тест = 1; + ТЗ.ЗаполнитьЗначения(3,""); + + юТест.ПроверитьРавенство(ТЗ[0].Тест, 3); +КонецПроцедуры + +Процедура ТестДолжен_Проверить_Найти_СПустымСпискомКолонок() Экспорт + ТЗ = Новый ТаблицаЗначений(); + ТЗ.Колонки.Добавить("Тест"); + ТЗ.Добавить().Тест = -3; + ТЗ.Добавить().Тест = 7; + Рез = ТЗ.Найти(7,""); + + юТест.ПроверитьНеРавенство(Рез, Неопределено); +КонецПроцедуры + +Процедура ТестДолжен_Проверить_СкопироватьКолонки_СПустымСпискомКолонок() Экспорт + ТЗ = Новый ТаблицаЗначений(); + ТЗ.Колонки.Добавить("Тест"); + ТЗ.Добавить().Тест = 1; + ТЗ2 = ТЗ.СкопироватьКолонки(); + + юТест.ПроверитьРавенство(ТЗ2.Колонки.Количество(), 1); + юТест.ПроверитьРавенство(ТЗ2.Колонки[0].Имя, "Тест"); +КонецПроцедуры + +Процедура ТестДолжен_Проверить_Скопировать_СПустымСпискомКолонок() Экспорт + ТЗ = Новый ТаблицаЗначений(); + ТЗ.Колонки.Добавить("Тест"); + ТЗ.Добавить().Тест = 1; + ТЗ.Добавить().Тест = 2; + ТЗ2 = ТЗ.Скопировать(,""); + + юТест.ПроверитьРавенство(ТЗ2.Количество(), 2); + юТест.ПроверитьРавенство(ТЗ2.Колонки.Количество(), 1); + юТест.ПроверитьРавенство(ТЗ2.Колонки[0].Имя, "Тест"); +КонецПроцедуры + +Процедура ТестДолжен_ПроверитьИтогПоКолонкеСОписаниемТипов_Строка() Экспорт + ТЗ = Новый ТаблицаЗначений(); + ТЗ.Колонки.Добавить("Тест", Новый ОписаниеТипов("Строка")); + ТЗ.Добавить().Тест = -3; + ТЗ.Добавить().Тест = "7"; + ТЗ.Добавить().Тест = "ц5"; + + юТест.ПроверитьРавенство(ТЗ.Итог("Тест"), 4); +КонецПроцедуры + +Процедура ТестДолжен_ПроверитьИтогПоКолонкеСОписаниемТипов_СтрокаЧисло() Экспорт + ТЗ = Новый ТаблицаЗначений(); + ТЗ.Колонки.Добавить("Тест", Новый ОписаниеТипов("Строка,Число")); + ТЗ.Добавить().Тест = -3; + ТЗ.Добавить().Тест = "7"; + ТЗ.Добавить().Тест = "ц5"; + + юТест.ПроверитьРавенство(ТЗ.Итог("Тест"), -3); +КонецПроцедуры + +Процедура ТестДолжен_ПроверитьИтогПоКолонкеСОписаниемТипов_СтрокаДата() Экспорт + ТЗ = Новый ТаблицаЗначений(); + ТЗ.Колонки.Добавить("Тест", Новый ОписаниеТипов("Строка,Дата")); + ТЗ.Добавить().Тест = -3; + ТЗ.Добавить().Тест = "7"; + ТЗ.Добавить().Тест = "ц5"; + + юТест.ПроверитьРавенство(ТЗ.Итог("Тест"), Неопределено); +КонецПроцедуры + +Процедура ТестДолжен_ПроверитьИтогПоКолонкеСОписаниемТипов_СтрокаБезЧисел() Экспорт + ТЗ = Новый ТаблицаЗначений(); + ТЗ.Колонки.Добавить("Тест", Новый ОписаниеТипов("Строка")); + ТЗ.Добавить().Тест = "без"; + ТЗ.Добавить().Тест = "числовых"; + ТЗ.Добавить().Тест = "значений"; + + юТест.ПроверитьРавенство(ТЗ.Итог("Тест"), 0); +КонецПроцедуры + +Процедура ТестДолжен_ПроверитьИтогПоКолонкеСОписаниемТипов_СтрокаЧислоБезЧисел() Экспорт + ТЗ = Новый ТаблицаЗначений(); + ТЗ.Колонки.Добавить("Тест", Новый ОписаниеТипов("Строка,Число")); + ТЗ.Добавить().Тест = "без"; + ТЗ.Добавить().Тест = "числовых"; + ТЗ.Добавить().Тест = "значений"; + + юТест.ПроверитьРавенство(ТЗ.Итог("Тест"), 0); +КонецПроцедуры + +Процедура ТестДолжен_ПроверитьИтогПоКолонкеСОписаниемТипов_СтрокаДатаБезЧисел() Экспорт + ТЗ = Новый ТаблицаЗначений(); + ТЗ.Колонки.Добавить("Тест", Новый ОписаниеТипов("Строка,Дата")); + ТЗ.Добавить().Тест = "без"; + ТЗ.Добавить().Тест = "числовых"; + ТЗ.Добавить().Тест = "значений"; + + юТест.ПроверитьРавенство(ТЗ.Итог("Тест"), Неопределено); +КонецПроцедуры + +Процедура ТестДолжен_ПроверитьИтогПоКолонкеБезОписанияТипов_БезЧисел() Экспорт + ТЗ = Новый ТаблицаЗначений(); + ТЗ.Колонки.Добавить("Тест"); + ТЗ.Добавить().Тест = "без"; + ТЗ.Добавить().Тест = "числовых"; + ТЗ.Добавить().Тест = "значений"; + + юТест.ПроверитьРавенство(ТЗ.Итог("Тест"), 0); +КонецПроцедуры + +Процедура ТестДолжен_ПроверитьИсключениеПриНеверномИмениКолонкиВОтборе() Экспорт + ТЗ = Новый ТаблицаЗначений(); + ТЗ.Колонки.Добавить("Тест"); + ТЗ.Добавить().Тест = -3; + ТЗ.Добавить().Тест = 7; + Фильтр = Новый Структура("Тест,Тест2",7,7); + + Попытка + Рез = ТЗ.НайтиСтроки(Фильтр); + Исключение + юТест.ПроверитьРавенство(Найти(ИнформацияОбОшибке().Описание,"NullException"), 0, "ArgumentNull"); + Возврат; + КонецПопытки; + + ВызватьИсключение "Ожидали исключение, но его не было"; +КонецПроцедуры + +Процедура ТестДолжен_ПроверитьЗапятуюВИменахКолонок_БезПустых() Экспорт + ТЗ = Новый ТаблицаЗначений(); + ТЗ.Колонки.Добавить("Тест"); + ТЗ.Колонки.Добавить("Тест2"); + ТЗ.Добавить().Тест = -3; + ТЗ.Добавить().Тест = 7; + ТЗ.Свернуть(", Тест" , "Тест2,"); +КонецПроцедуры + +Процедура ТестДолжен_ПроверитьЗапятуюВИменахКолонок_СПустыми() Экспорт + ТЗ = Новый ТаблицаЗначений(); + ТЗ.Колонки.Добавить("Тест"); + ТЗ.Колонки.Добавить("Тест2"); + ТЗ.Добавить().Тест = -3; + ТЗ.Добавить().Тест = 7; + + Попытка + ТЗ.Свернуть("Тест, " , "Тест2"); + Исключение + Возврат; + КонецПопытки; + + ВызватьИсключение "Ожидали исключение, но его не было"; +КонецПроцедуры + +Процедура ТестДолжен_ПроверитьИсключениеДляИндекса() Экспорт + ТЗ = Новый ТаблицаЗначений(); + ТЗ.Колонки.Добавить("Тест"); + ТЗ.Добавить().Тест = -1; + + Попытка + Индекс = ТЗ.Индекс("Тест"); + Исключение + Возврат; + КонецПопытки; + + ВызватьИсключение "Ожидали исключение, но его не было"; +КонецПроцедуры + +Процедура ТестДолжен_ВызватьИсключениеПриДобавленииКолонкиСНевернымИменем() Экспорт + ТЗ = Новый ТаблицаЗначений(); + Попытка + ТЗ.Колонки.Добавить("!@#"); + Исключение + Возврат; + КонецПопытки; + + ВызватьИсключение "Должно было быть выдано исключение, но его не было"; +КонецПроцедуры + +Процедура ТестДолжен_ВызватьИсключениеПриВставкеКолонкиСНевернымИменем() Экспорт + ТЗ = Новый ТаблицаЗначений(); + Попытка + ТЗ.Колонки.Вставить(0,"!@#"); + Исключение + Возврат; + КонецПопытки; + + ВызватьИсключение "Должно было быть выдано исключение, но его не было"; +КонецПроцедуры + +Процедура ТестДолжен_ВызватьИсключениеНаПоискеИндексаКолонкиСНевернымПримитивнымТипом() Экспорт + ТЗ = Новый ТаблицаЗначений(); + Попытка + ТЗ.Колонки.Индекс(0); + Исключение + Ошибка = ИнформацияОбОшибке().Описание; + юТест.ПроверитьНеРавенство(Найти(Ошибка,"Неверный тип аргумента"), 0, "Неверный вид ошибки: "+Ошибка); + Возврат; + КонецПопытки; + + ВызватьИсключение "Должно было быть выдано исключение, но его не было"; +КонецПроцедуры + +Процедура ТестДолжен_ВызватьИсключениеНаПоискеИндексаКолонкиСНевернымОбъектнымТипом() Экспорт + ТЗ = Новый ТаблицаЗначений(); + Попытка + ТЗ.Колонки.Индекс(ТЗ); + Исключение + Ошибка = ИнформацияОбОшибке().Описание; + юТест.ПроверитьНеРавенство(Найти(Ошибка,"Неверный тип аргумента"), 0, "Неверный вид ошибки: "+Ошибка); + Возврат; + КонецПопытки; + + ВызватьИсключение "Должно было быть выдано исключение, но его не было"; +КонецПроцедуры + +Процедура ТестДолжен_ПроверитьИсключениеПолученияКолонкиСНевернымНомером() Экспорт + ТЗ = Новый ТаблицаЗначений(); + ТЗ.Колонки.Добавить("Тест"); + СтрокаТЗ = ТЗ.Добавить(); + + БылоИсключение = Ложь; + Попытка + Рез = СтрокаТЗ.Получить(-1); + Исключение + Ошибка = ИнформацияОбОшибке().Описание; + юТест.ПроверитьНеРавенство(Найти(Ошибка,"Значение индекса выходит за пределы"), 0, "Неверный вид ошибки: "+Ошибка); + БылоИсключение = Истина; + КонецПопытки; + юТест.ПроверитьИстину(БылоИсключение, "Получение колонки с неверным номером"); + + БылоИсключение = Ложь; + Попытка + Рез = СтрокаТЗ[-1]; + Исключение + Ошибка = ИнформацияОбОшибке().Описание; + юТест.ПроверитьНеРавенство(Найти(Ошибка,"Значение индекса выходит за пределы"), 0, "Неверный вид ошибки: "+Ошибка); + БылоИсключение = Истина; + КонецПопытки; + юТест.ПроверитьИстину(БылоИсключение, "Получение колонки по неверному индексу"); + +КонецПроцедуры