Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions src/ScriptEngine/Machine/Contexts/EnumerationContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ This Source Code Form is subject to the terms of the
----------------------------------------------------------*/

using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using OneScript.Commons;
using OneScript.Contexts;
Expand All @@ -20,7 +21,7 @@ public abstract class EnumerationContext : PropertyNameIndexAccessor, ICollectio
private readonly IndexedNameValueCollection<EnumerationValue> _values;
private readonly List<BslPropertyInfo> _definitions;
private readonly TypeDescriptor _valuesType;
private readonly HashSet<int> _checkedDeprecatedProps = new HashSet<int>();
private readonly ConcurrentDictionary<int, byte> _checkedDeprecatedProps = new ConcurrentDictionary<int, byte>();

protected EnumerationContext(TypeDescriptor typeRepresentation, TypeDescriptor valuesType) : base(typeRepresentation)
{
Expand Down Expand Up @@ -85,15 +86,13 @@ private EnumerationValue GetPropValueInternal(int propNum)

private void WarnDeprecation(int propNum)
{
if (_checkedDeprecatedProps.Contains(propNum))
if (!_checkedDeprecatedProps.TryAdd(propNum, 0))
return;

if (GetPropertyInfo(propNum) is SystemPropertyInfo { IsDeprecated: true })
{
SystemLogger.Write($"Обращение к устаревшему свойству {GetPropertyInfo(propNum).Name}.");
}

_checkedDeprecatedProps.Add(propNum);
}

public override string GetPropName(int propNum)
Expand Down
60 changes: 59 additions & 1 deletion src/Tests/OneScript.Core.Tests/ObsoleteMembersTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ This Source Code Form is subject to the terms of the
----------------------------------------------------------*/

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading.Tasks;
using FluentAssertions;
using Moq;
using OneScript.Exceptions;
Expand Down Expand Up @@ -166,5 +168,61 @@ public void DeprecatedEnumValueHasWarning()
_messages.Should().HaveCount(1)
.And.Contain(x => x.Contains("СтароеЗначение2", StringComparison.InvariantCultureIgnoreCase));
}

[Fact]
public void ConcurrentEnumValueAccessDoesNotThrow()
{
var enumInstance = CreateDeprecatedEnumInstance();

var exceptions = new ConcurrentBag<Exception>();
Parallel.For(0, 1000, i =>
{
try
{
_ = enumInstance["Значение1"];
}
catch (Exception e)
{
exceptions.Add(e);
}
});

exceptions.Should().BeEmpty();
_messages.Should().BeEmpty();
}

[Fact]
public void ConcurrentDeprecatedEnumValueAccessWarnsOnce()
{
var enumInstance = CreateDeprecatedEnumInstance();

var exceptions = new ConcurrentBag<Exception>();
Parallel.For(0, 1000, i =>
{
try
{
_ = enumInstance["СтароеЗначение2"];
}
catch (Exception e)
{
exceptions.Add(e);
}
});

exceptions.Should().BeEmpty();
_messages.Should().HaveCount(1)
.And.Contain(x => x.Contains("СтароеЗначение2", StringComparison.InvariantCultureIgnoreCase));
}

private static ClrEnumWrapper<DeprecatedEnum> CreateDeprecatedEnumInstance()
{
var env = new RuntimeEnvironment();
var discoverer = new ContextDiscoverer(new DefaultTypeManager(), Mock.Of<IGlobalsManager>(), new TinyIocImplementation());
discoverer.DiscoverGlobalContexts(env, typeof(ObsoleteMembersTest).Assembly, t => t == typeof(DeprecatedEnum));

var enumInstance = env.GetGlobalProperty("НовоеПеречисление") as ClrEnumWrapper<DeprecatedEnum>;
enumInstance.Should().NotBeNull();
return enumInstance!;
}
}
}
}
22 changes: 22 additions & 0 deletions tests/tasks.os
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
ВсеТесты.Добавить("ТестДолжен_ПроверитьЧтоОжиданиеНеСтираетНовыеЗадания");
ВсеТесты.Добавить("ТестДолжен_ПроверитьЧтоВИнформацииОбОшибкеЕстьСтекВызовов");
ВсеТесты.Добавить("ТестДолжен_ПроверитьЧтоОбработчикиСобытийВызываютсяВФоновомЗадании");
ВсеТесты.Добавить("ТестДолжен_ПроверитьПараллельноеЧтениеЗначенияСистемногоПеречисления");

Возврат ВсеТесты;

Expand Down Expand Up @@ -647,6 +648,27 @@

КонецПроцедуры

Процедура ПрочитатьЗначениеПеречисления() Экспорт
Значение = НаправлениеПоиска.СКонца;
Если Значение = Неопределено Тогда
ВызватьИсключение "Не удалось прочитать значение системного перечисления";
КонецЕсли;
КонецПроцедуры

Процедура ТестДолжен_ПроверитьПараллельноеЧтениеЗначенияСистемногоПеречисления() Экспорт

КоличествоЗаданий = 200;
Задания = Новый Массив;

Для НомерЗадания = 1 По КоличествоЗаданий Цикл
Задания.Добавить(ФоновыеЗадания.Выполнить(ЭтотОбъект, "ПрочитатьЗначениеПеречисления", , Истина));
КонецЦикла;

ФоновыеЗадания.ОжидатьВсе(Задания);
ПроверитьОтсутствиеОшибокВЗаданиях(Задания);

КонецПроцедуры

Процедура Пустышка() Экспорт
КонецПроцедуры

Expand Down
Loading