diff --git a/packagedef b/packagedef index 8613d52..52360ce 100644 --- a/packagedef +++ b/packagedef @@ -4,7 +4,7 @@ // Описание.Имя("configor") - .Версия("0.12.0") + .Версия("0.13.0") .Автор("Khorev Aleksey") .АдресАвтора("Khorevaa@gmail.com") .Описание("Библиотека для работы с конфигурационными файлами в формате json, yaml") @@ -12,13 +12,14 @@ .ВключитьФайл("src") .ВключитьФайл("docs") .ЗависитОт("logos") - .ЗависитОт("oscript-yaml") + .ЗависитОт("oscript-yaml", "0.3.0") .ЗависитОт("asserts") .ЗависитОт("fluent", "0.6.0") .ЗависитОт("notify", "0.2.0") .ЗависитОт("tempfiles") .ЗависитОт("1connector", "2.3.3") .ЗависитОт("reflector", "0.3.1") + .ЗависитОт("annotations", "1.3.0") .РазработкаЗависитОт("coverage", "0.6.1") .РазработкаЗависитОт("1testrunner", "1.9.2") .РазработкаЗависитОт("1bdd", "1.14.0") @@ -26,4 +27,7 @@ .РазработкаЗависитОт("winow", "0.11.0") .ОпределяетКласс("МенеджерПараметров", "src/Классы/МенеджерПараметров.os") .ОпределяетКласс("КонструкторПараметров", "src/Классы/КонструкторПараметров.os") + .ОпределяетКласс("АннотацияЗначениеПоУмолчанию", "src/Классы/АннотацияЗначениеПоУмолчанию.os") + .ОпределяетКласс("АннотацияСиноним", "src/Классы/АннотацияСиноним.os") + .ОпределяетКласс("АннотацияВложенныйДТО", "src/Классы/АннотацияВложенныйДТО.os") ; diff --git "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/internal/\320\232\320\273\320\260\321\201\321\201\321\213/\320\236\320\277\320\270\321\201\320\260\320\275\320\270\320\265\320\237\320\276\320\273\321\217\320\224\320\242\320\236.os" "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/internal/\320\232\320\273\320\260\321\201\321\201\321\213/\320\236\320\277\320\270\321\201\320\260\320\275\320\270\320\265\320\237\320\276\320\273\321\217\320\224\320\242\320\236.os" new file mode 100644 index 0000000..42fd9cd --- /dev/null +++ "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/internal/\320\232\320\273\320\260\321\201\321\201\321\213/\320\236\320\277\320\270\321\201\320\260\320\275\320\270\320\265\320\237\320\276\320\273\321\217\320\224\320\242\320\236.os" @@ -0,0 +1,88 @@ +// Описание одного поля DTO-класса, полученное из аннотаций свойства + +Перем Имя Экспорт; // Строка - имя свойства класса +Перем Тип Экспорт; // Тип - целевой тип значения из аннотации Тип +Перем ЗначениеПоУмолчанию Экспорт; // Произвольный - значение по умолчанию +Перем Синоним Экспорт; // Строка - альтернативное имя ключа в конфигурации +Перем Обязательное Экспорт; // Булево - признак обязательности (нет ЗначениеПоУмолчанию) +Перем ОписанияВложенныхПолей Экспорт; // Массив из ОписаниеПоляДТО - описания полей вложенного DTO + +// Конструктор описания поля +// +// Параметры: +// ИмяПоля - Строка - имя свойства класса +// +Процедура ПриСозданииОбъекта(Знач ИмяПоля) + + Имя = ИмяПоля; + Тип = Неопределено; + ЗначениеПоУмолчанию = Неопределено; + Синоним = Неопределено; + Обязательное = Истина; + ОписанияВложенныхПолей = Неопределено; + +КонецПроцедуры + +// Устанавливает значение по умолчанию, делая поле необязательным +// +// Параметры: +// Значение - Произвольный - значение по умолчанию +// +Процедура УстановитьЗначениеПоУмолчанию(Знач Значение) Экспорт + + ЗначениеПоУмолчанию = Значение; + Обязательное = Ложь; + +КонецПроцедуры + +// Устанавливает тип значения явно (из аннотации &Тип) +// +// Параметры: +// НовыйТип - Тип - целевой тип значения +// +Процедура УстановитьТип(Знач НовыйТип) Экспорт + Тип = НовыйТип; +КонецПроцедуры + +// Устанавливает синоним поля +// +// Параметры: +// НовыйСиноним - Строка - альтернативное имя ключа в конфигурации +// +Процедура УстановитьСиноним(Знач НовыйСиноним) Экспорт + Синоним = НовыйСиноним; +КонецПроцедуры + +// Помечает поле как вложенный DTO и сохраняет описания его полей +// +// Параметры: +// ОписанияПолей - Массив из ОписаниеПоляДТО - описания полей вложенного DTO +// +Процедура УстановитьВложенныйДТО(Знач ОписанияПолей) Экспорт + ОписанияВложенныхПолей = ОписанияПолей; +КонецПроцедуры + +// Возвращает признак того, что поле является вложенным DTO +// +// Возвращаемое значение: +// Булево - Истина, если поле описано как вложенный DTO +// +Функция ЭтоВложенныйДТО() Экспорт + Возврат Не ОписанияВложенныхПолей = Неопределено; +КонецФункции + +// Возвращает ключ для поиска в конфигурации +// Если задан синоним - возвращает его, иначе - имя свойства +// +// Возвращаемое значение: +// Строка - ключ для поиска в конфигурации +// +Функция КлючКонфигурации() Экспорт + + Если Не Синоним = Неопределено Тогда + Возврат Синоним; + КонецЕсли; + + Возврат Имя; + +КонецФункции diff --git "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/internal/\320\232\320\273\320\260\321\201\321\201\321\213/\320\236\320\277\320\270\321\201\320\260\321\202\320\265\320\273\321\214\320\224\320\242\320\236.os" "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/internal/\320\232\320\273\320\260\321\201\321\201\321\213/\320\236\320\277\320\270\321\201\320\260\321\202\320\265\320\273\321\214\320\224\320\242\320\236.os" new file mode 100644 index 0000000..72bd020 --- /dev/null +++ "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/internal/\320\232\320\273\320\260\321\201\321\201\321\213/\320\236\320\277\320\270\321\201\320\260\321\202\320\265\320\273\321\214\320\224\320\242\320\236.os" @@ -0,0 +1,96 @@ +#Использовать annotations +#Использовать reflector + +Перем КонтейнерАннотаций; // КонтейнерАннотаций - определения поддерживаемых аннотаций + +// Описывает класс DTO: читает аннотации экспортных свойств и возвращает массив описаний полей +// +// Параметры: +// КлассОбъект - Объект - экземпляр DTO-класса с аннотированными свойствами +// +// Возвращаемое значение: +// Массив из ОписаниеПоляДТО - массив описаний полей DTO +// +Функция ОписатьКласс(Знач КлассОбъект) Экспорт + + РефлекторОбъекта = Новый РефлекторОбъекта(КлассОбъект); + Свойства = РефлекторОбъекта.ПолучитьТаблицуСвойств(Неопределено, Истина); + + СтандартныйРефлектор = Новый Рефлектор; + + ОписанияПолей = Новый Массив; + + Для Каждого Свойство Из Свойства Цикл + + Если Не Свойство.Экспорт Тогда + Продолжить; + КонецЕсли; + + ОписаниеПоля = Новый ОписаниеПоляДТО(Свойство.Имя); + + Для Каждого Аннотация Из Свойство.Аннотации Цикл + + ИмяАннотации = Врег(Аннотация.Имя); + + Если ИмяАннотации = "ТИП" Тогда + ЗначениеТипа = РаботаСАннотациями.ПолучитьЗначениеПараметраАннотации(Аннотация); + ОписаниеПоля.УстановитьТип(Тип(ЗначениеТипа)); + Продолжить; + КонецЕсли; + + ОпределениеАннотации = КонтейнерАннотаций.ПолучитьОпределениеАннотации(Аннотация.Имя); + + Если ОпределениеАннотации = Неопределено Тогда + Продолжить; + КонецЕсли; + + ОбъектАннотации = ОпределениеАннотации.СоздатьОбъектАннотации(Аннотация); + + Если ИмяАннотации = "ЗНАЧЕНИЕПОУМОЛЧАНИЮ" Тогда + + ОписаниеПоля.УстановитьЗначениеПоУмолчанию(ОбъектАннотации.Значение()); + + ИначеЕсли ИмяАннотации = "СИНОНИМ" Тогда + + ОписаниеПоля.УстановитьСиноним(ОбъектАннотации.Синоним()); + + ИначеЕсли ИмяАннотации = "ВЛОЖЕННЫЙДТО" Тогда + + ВложенныйОбъект = СтандартныйРефлектор.ПолучитьСвойство(КлассОбъект, Свойство.Имя); + + Если ВложенныйОбъект = Неопределено Тогда + + ИмяКлассаДТО = ОбъектАннотации.ИмяКлассаДТО(); + + Если ИмяКлассаДТО = "" Тогда + ВызватьИсключение "Свойство """ + Свойство.Имя + """ помечено как вложенный DTO," + + " но не инициализировано в конструкторе и класс не указан в аннотации"; + КонецЕсли; + + ВложенныйОбъект = Новый(ИмяКлассаДТО); + СтандартныйРефлектор.УстановитьСвойство(КлассОбъект, Свойство.Имя, ВложенныйОбъект); + + КонецЕсли; + + ОписаниеПоля.УстановитьВложенныйДТО(ОписатьКласс(ВложенныйОбъект)); + + КонецЕсли; + + КонецЦикла; + + ОписанияПолей.Добавить(ОписаниеПоля); + + КонецЦикла; + + Возврат ОписанияПолей; + +КонецФункции + +Процедура ПриСозданииОбъекта() + + КонтейнерАннотаций = Новый КонтейнерАннотаций; + КонтейнерАннотаций.ДобавитьАннотацию(Тип("АннотацияЗначениеПоУмолчанию")); + КонтейнерАннотаций.ДобавитьАннотацию(Тип("АннотацияСиноним")); + КонтейнерАннотаций.ДобавитьАннотацию(Тип("АннотацияВложенныйДТО")); + +КонецПроцедуры diff --git "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\220\320\275\320\275\320\276\321\202\320\260\321\206\320\270\321\217\320\222\320\273\320\276\320\266\320\265\320\275\320\275\321\213\320\271\320\224\320\242\320\236.os" "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\220\320\275\320\275\320\276\321\202\320\260\321\206\320\270\321\217\320\222\320\273\320\276\320\266\320\265\320\275\320\275\321\213\320\271\320\224\320\242\320\236.os" new file mode 100644 index 0000000..c1b37ca --- /dev/null +++ "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\220\320\275\320\275\320\276\321\202\320\260\321\206\320\270\321\217\320\222\320\273\320\276\320\266\320\265\320\275\320\275\321\213\320\271\320\224\320\242\320\236.os" @@ -0,0 +1,26 @@ +Перем _ИмяКлассаДТО; // Строка - имя класса вложенного DTO, пустая строка если не указано + +// Возвращает имя аннотации +// +// Возвращаемое значение: +// Строка - имя аннотации +// +Функция ИмяАннотации() Экспорт + Возврат "ВложенныйДТО"; +КонецФункции + +// Возвращает имя класса вложенного DTO +// Пустая строка означает, что класс не указан и объект +// должен быть создан в конструкторе владеющего класса +// +// Возвращаемое значение: +// Строка - имя класса вложенного DTO +// +Функция ИмяКлассаДТО() Экспорт + Возврат _ИмяКлассаДТО; +КонецФункции + +&Аннотация("ВложенныйДТО") +Процедура ПриСозданииОбъекта(Значение = "") Экспорт + _ИмяКлассаДТО = ?(Значение = Неопределено, "", Значение); +КонецПроцедуры diff --git "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\220\320\275\320\275\320\276\321\202\320\260\321\206\320\270\321\217\320\227\320\275\320\260\321\207\320\265\320\275\320\270\320\265\320\237\320\276\320\243\320\274\320\276\320\273\321\207\320\260\320\275\320\270\321\216.os" "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\220\320\275\320\275\320\276\321\202\320\260\321\206\320\270\321\217\320\227\320\275\320\260\321\207\320\265\320\275\320\270\320\265\320\237\320\276\320\243\320\274\320\276\320\273\321\207\320\260\320\275\320\270\321\216.os" new file mode 100644 index 0000000..11e00fe --- /dev/null +++ "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\220\320\275\320\275\320\276\321\202\320\260\321\206\320\270\321\217\320\227\320\275\320\260\321\207\320\265\320\275\320\270\320\265\320\237\320\276\320\243\320\274\320\276\320\273\321\207\320\260\320\275\320\270\321\216.os" @@ -0,0 +1,24 @@ +Перем _Значение; + +// Возвращает имя аннотации +// +// Возвращаемое значение: +// Строка - имя аннотации +// +Функция ИмяАннотации() Экспорт + Возврат "ЗначениеПоУмолчанию"; +КонецФункции + +// Возвращает значение по умолчанию +// +// Возвращаемое значение: +// Произвольный - значение по умолчанию +// +Функция Значение() Экспорт + Возврат _Значение; +КонецФункции + +&Аннотация("ЗначениеПоУмолчанию") +Процедура ПриСозданииОбъекта(Значение) Экспорт + _Значение = Значение; +КонецПроцедуры diff --git "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\220\320\275\320\275\320\276\321\202\320\260\321\206\320\270\321\217\320\241\320\270\320\275\320\276\320\275\320\270\320\274.os" "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\220\320\275\320\275\320\276\321\202\320\260\321\206\320\270\321\217\320\241\320\270\320\275\320\276\320\275\320\270\320\274.os" new file mode 100644 index 0000000..133c89b --- /dev/null +++ "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\220\320\275\320\275\320\276\321\202\320\260\321\206\320\270\321\217\320\241\320\270\320\275\320\276\320\275\320\270\320\274.os" @@ -0,0 +1,24 @@ +Перем _Синоним; + +// Возвращает имя аннотации +// +// Возвращаемое значение: +// Строка - имя аннотации +// +Функция ИмяАннотации() Экспорт + Возврат "Синоним"; +КонецФункции + +// Возвращает синоним (альтернативное имя ключа в конфигурации) +// +// Возвращаемое значение: +// Строка - синоним свойства +// +Функция Синоним() Экспорт + Возврат _Синоним; +КонецФункции + +&Аннотация("Синоним") +Процедура ПриСозданииОбъекта(Значение) Экспорт + _Синоним = Значение; +КонецПроцедуры diff --git "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\234\320\265\320\275\320\265\320\264\320\266\320\265\321\200\320\237\320\260\321\200\320\260\320\274\320\265\321\202\321\200\320\276\320\262.os" "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\234\320\265\320\275\320\265\320\264\320\266\320\265\321\200\320\237\320\260\321\200\320\260\320\274\320\265\321\202\321\200\320\276\320\262.os" index 273f5a2..53bb7ad 100644 --- "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\234\320\265\320\275\320\265\320\264\320\266\320\265\321\200\320\237\320\260\321\200\320\260\320\274\320\265\321\202\321\200\320\276\320\262.os" +++ "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\234\320\265\320\275\320\265\320\264\320\266\320\265\321\200\320\237\320\260\321\200\320\260\320\274\320\265\321\202\321\200\320\276\320\262.os" @@ -19,6 +19,9 @@ Перем ВнутреннийКонструкторПараметров; // Класс КонструкторПараметров Перем ИспользуетсяКонструкторПараметров; // булево +Перем ВнутреннийОписательДТО; // Класс ОписательДТО +Перем РеестрКлассовПараметров; // Соответствие: КлассОбъект -> Структура(Префикс, ОписанияПолей) + Перем Лог; // Логгер #Область Экспортных_процедур @@ -310,10 +313,131 @@ КонецФункции +// Регистрирует класс DTO-параметров по префиксу +// Считывает аннотации свойств класса и сохраняет описания полей +// +// Параметры: +// КлассОбъект - Объект - экземпляр DTO-класса с аннотированными свойствами +// Префикс - Строка - ключ верхнего уровня в конфигурации +// +Процедура ЗарегистрироватьКлассПараметров(Знач КлассОбъект, Знач Префикс) Экспорт + + ПроверитьСвободенЛиПрефикс(КлассОбъект, Префикс); + + ОписанияПолей = ВнутреннийОписательДТО.ОписатьКласс(КлассОбъект); + + Лог.Отладка("Зарегистрирован класс параметров с префиксом <%1>, полей: %2", Префикс, ОписанияПолей.Количество()); + + Запись = Новый Структура("Префикс, ОписанияПолей", Префикс, ОписанияПолей); + РеестрКлассовПараметров.Вставить(КлассОбъект, Запись); + +КонецПроцедуры + +// Заполняет свойства объекта DTO из прочитанных параметров +// Использует зарегистрированные описания полей и префикс для маппинга +// +// Параметры: +// КлассОбъект - Объект - экземпляр DTO-класса для заполнения, +// ранее переданный в ЗарегистрироватьКлассПараметров +// +Процедура ЗаполнитьОбъектПараметров(Знач КлассОбъект) Экспорт + + Запись = РеестрКлассовПараметров[КлассОбъект]; + + Если Запись = Неопределено Тогда + ВызватьИсключение "Класс параметров не зарегистрирован," + + " перед заполнением вызовите ЗарегистрироватьКлассПараметров"; + КонецЕсли; + + ЗаполнитьПоОписаниям(КлассОбъект, Запись.ОписанияПолей, Запись.Префикс); + +КонецПроцедуры + #КонецОбласти #Область Вспомогательные_процедуры_и_функции +// Проверяет, что префикс не занят другим зарегистрированным классом параметров +// Повторная регистрация того же объекта разрешена и заменяет прежнюю запись +// Префиксы сравниваются без учета регистра, так как индекс параметров регистронезависим +// +// Параметры: +// КлассОбъект - Объект - регистрируемый экземпляр DTO-класса +// Префикс - Строка - ключ верхнего уровня в конфигурации +// +Процедура ПроверитьСвободенЛиПрефикс(Знач КлассОбъект, Знач Префикс) + + Для Каждого ЭлементРеестра Из РеестрКлассовПараметров Цикл + + Если ЭлементРеестра.Ключ = КлассОбъект Тогда + Продолжить; + КонецЕсли; + + Если НРег(ЭлементРеестра.Значение.Префикс) = НРег(Префикс) Тогда + ВызватьИсключение "Префикс """ + Префикс + + """ уже занят другим зарегистрированным классом параметров"; + КонецЕсли; + + КонецЦикла; + +КонецПроцедуры + +// Заполняет свойства объекта по описаниям полей, +// рекурсивно спускаясь во вложенные DTO +// +// Параметры: +// Объект - Объект - заполняемый объект +// ОписанияПолей - Массив из ОписаниеПоляДТО - описания полей этого объекта +// Префикс - Строка - ключ конфигурации, соответствующий текущему уровню вложенности +// +Процедура ЗаполнитьПоОписаниям(Знач Объект, Знач ОписанияПолей, Знач Префикс) + + ОбъектРефлектор = Новый Рефлектор; + + Для Каждого ОписаниеПоля Из ОписанияПолей Цикл + + ПолныйКлюч = Префикс + "." + ОписаниеПоля.КлючКонфигурации(); + + Если ОписаниеПоля.ЭтоВложенныйДТО() Тогда + + ВложенныйОбъект = ОбъектРефлектор.ПолучитьСвойство(Объект, ОписаниеПоля.Имя); + + Если ВложенныйОбъект = Неопределено Тогда + ВызватьИсключение "Свойство """ + ОписаниеПоля.Имя + + """ описано как вложенный DTO, но не инициализировано на момент заполнения"; + КонецЕсли; + + Лог.Отладка("Рекурсивное заполнение вложенного DTO <%1> по ключу <%2>", ОписаниеПоля.Имя, ПолныйКлюч); + ЗаполнитьПоОписаниям(ВложенныйОбъект, ОписаниеПоля.ОписанияВложенныхПолей, ПолныйКлюч); + Продолжить; + + КонецЕсли; + + ЗначениеИзКонфига = Параметр(ПолныйКлюч); + + Если Не ЗначениеИзКонфига = Неопределено Тогда + + ЗначениеИзКонфига = ПривестиЗначениеКТипу(ЗначениеИзКонфига, ОписаниеПоля); + Лог.Отладка("Установка свойства <%1> из параметра <%2>", ОписаниеПоля.Имя, ПолныйКлюч); + ОбъектРефлектор.УстановитьСвойство(Объект, ОписаниеПоля.Имя, ЗначениеИзКонфига); + + ИначеЕсли Не ОписаниеПоля.Обязательное Тогда + + Лог.Отладка("Свойство <%1> не найдено в конфиге, используется значение по умолчанию", ОписаниеПоля.Имя); + ОбъектРефлектор.УстановитьСвойство(Объект, ОписаниеПоля.Имя, ОписаниеПоля.ЗначениеПоУмолчанию); + + Иначе + + ВызватьИсключение "Обязательный параметр """ + ПолныйКлюч + + """ (свойство """ + ОписаниеПоля.Имя + + """) не задан в конфигурации и не имеет значения по умолчанию"; + + КонецЕсли; + + КонецЦикла; + +КонецПроцедуры + Функция ПолучитьКонструкторПараметров() Конструктор = Новый КонструкторПараметров(); @@ -322,6 +446,72 @@ КонецФункции +// Разбирает строковое представление булева значения +// Строка, не входящая в список допустимых значений, вызывает исключение +// +// Параметры: +// Значение - Строка - строковое представление булева значения +// +// Возвращаемое значение: +// Булево - разобранное значение +// +Функция ПривестиСтрокуКБулево(Знач Значение) + + СтрЗначение = ВРег(СокрЛП(Значение)); + + Если Не СтрРазделить("1,TRUE,ИСТИНА,ДА,YES,ON", ",").Найти(СтрЗначение) = Неопределено Тогда + Возврат Истина; + КонецЕсли; + + Если Не СтрРазделить("0,FALSE,ЛОЖЬ,НЕТ,NO,OFF", ",").Найти(СтрЗначение) = Неопределено Тогда + Возврат Ложь; + КонецЕсли; + + ВызватьИсключение "Невалидное булево значение"; + +КонецФункции + +Функция ПривестиЗначениеКТипу(Знач Значение, Знач ОписаниеПоля) + + ЦелевойТип = ОписаниеПоля.Тип; + + Если ЦелевойТип = Неопределено Тогда + Возврат Значение; + КонецЕсли; + + Если ТипЗнч(Значение) = ЦелевойТип Тогда + Возврат Значение; + КонецЕсли; + + Попытка + + Если ЦелевойТип = Тип("Дата") Тогда + Возврат XMLЗначение(Тип("Дата"), Значение); + Иначе + + Если ЦелевойТип = Тип("Булево") И ТипЗнч(Значение) = Тип("Строка") Тогда + Возврат ПривестиСтрокуКБулево(Значение); + КонецЕсли; + + ОписаниеТипов = Новый ОписаниеТипов(Строка(ЦелевойТип)); + Результат = ОписаниеТипов.ПривестиЗначение(Значение); + + Если ЦелевойТип = Тип("Число") И ТипЗнч(Значение) = Тип("Строка") Тогда + Если Результат = 0 И СокрЛП(Значение) <> "0" Тогда + ВызватьИсключение "Невалидное числовое значение"; + КонецЕсли; + КонецЕсли; + + Возврат Результат; + КонецЕсли; + + Исключение + ВызватьИсключение "Не удалось привести значение параметра """ + + ОписаниеПоля.Имя + """ (" + Значение + ") к типу " + ЦелевойТип; + КонецПопытки; + +КонецФункции + Процедура ВыполнитьЧтениеПровайдеров() КоллекцияПровайдеров = Новый ПроцессорКоллекций; @@ -471,6 +661,9 @@ ВнутреннийКонструкторПараметров = Неопределено; ИспользуетсяКонструкторПараметров = Ложь; + ВнутреннийОписательДТО = Новый ОписательДТО; + РеестрКлассовПараметров = Новый Соответствие; + КонецПроцедуры Функция ИнтерфейсРеализован(Интерфейс, КлассОбъект, ВыдатьОшибку = Ложь) diff --git "a/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\320\276\320\265\320\237\320\276\320\264\320\272\320\273\321\216\321\207\320\265\320\275\320\270\320\265.os" "b/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\320\276\320\265\320\237\320\276\320\264\320\272\320\273\321\216\321\207\320\265\320\275\320\270\320\265.os" new file mode 100644 index 0000000..1254f93 --- /dev/null +++ "b/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\320\276\320\265\320\237\320\276\320\264\320\272\320\273\321\216\321\207\320\265\320\275\320\270\320\265.os" @@ -0,0 +1,10 @@ +// Вложенный DTO: параметры подключения + +&ЗначениеПоУмолчанию("localhost") +Перем Хост Экспорт; + +&ЗначениеПоУмолчанию(5432) +Перем Порт Экспорт; + +Процедура ПриСозданииОбъекта() +КонецПроцедуры diff --git "a/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\320\276\320\265\320\237\320\276\320\264\320\272\320\273\321\216\321\207\320\265\320\275\320\270\320\265\320\241\320\242\320\270\320\277\320\260\320\274\320\270.os" "b/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\320\276\320\265\320\237\320\276\320\264\320\272\320\273\321\216\321\207\320\265\320\275\320\270\320\265\320\241\320\242\320\270\320\277\320\260\320\274\320\270.os" new file mode 100644 index 0000000..1c79b01 --- /dev/null +++ "b/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\320\276\320\265\320\237\320\276\320\264\320\272\320\273\321\216\321\207\320\265\320\275\320\270\320\265\320\241\320\242\320\270\320\277\320\260\320\274\320\270.os" @@ -0,0 +1,13 @@ +// Вложенный DTO с аннотациями типов + +&Тип("Строка") +Перем Хост Экспорт; + +&Тип("Число") +Перем Порт Экспорт; + +&Тип("Булево") +Перем SSL Экспорт; + +Процедура ПриСозданииОбъекта() +КонецПроцедуры diff --git "a/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236.os" "b/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236.os" new file mode 100644 index 0000000..524bf55 --- /dev/null +++ "b/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236.os" @@ -0,0 +1,10 @@ +// Тестовый DTO с аннотированными свойствами для проверки ОписательДТО и МенеджерПараметров + +&ЗначениеПоУмолчанию("localhost") +Перем АдресСервера Экспорт; + +&ЗначениеПоУмолчанию(8080) +Перем ПортСервера Экспорт; + +Процедура ПриСозданииОбъекта() +КонецПроцедуры diff --git "a/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\221\320\260\320\267\320\260\320\224\320\260\320\275\320\275\321\213\321\205.os" "b/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\221\320\260\320\267\320\260\320\224\320\260\320\275\320\275\321\213\321\205.os" new file mode 100644 index 0000000..32a3650 --- /dev/null +++ "b/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\221\320\260\320\267\320\260\320\224\320\260\320\275\320\275\321\213\321\205.os" @@ -0,0 +1,11 @@ +// DTO второго уровня: настройки базы данных с вложенным DTO подключения + +&ЗначениеПоУмолчанию("main_db") +Перем ИмяБазы Экспорт; + +&ВложенныйДТО +Перем Подключение Экспорт; + +Процедура ПриСозданииОбъекта() + Подключение = ЗагрузитьСценарий(ОбъединитьПути(ТекущийСценарий().Каталог, "ТестовоеПодключение.os")); +КонецПроцедуры diff --git "a/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\221\320\260\320\267\320\260\320\224\320\260\320\275\320\275\321\213\321\205\320\220\320\275\320\275\320\276\321\202\320\260\321\206\320\270\321\217.os" "b/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\221\320\260\320\267\320\260\320\224\320\260\320\275\320\275\321\213\321\205\320\220\320\275\320\275\320\276\321\202\320\260\321\206\320\270\321\217.os" new file mode 100644 index 0000000..0580c30 --- /dev/null +++ "b/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\221\320\260\320\267\320\260\320\224\320\260\320\275\320\275\321\213\321\205\320\220\320\275\320\275\320\276\321\202\320\260\321\206\320\270\321\217.os" @@ -0,0 +1,13 @@ +// DTO второго уровня: то же самое, что ТестовыйДТОБазаДанных, +// но вложенный DTO НЕ инициализируется в конструкторе - его создаёт +// ОписательДТО по имени класса, указанному параметром аннотации &ВложенныйДТО. +// Имя класса регистрируется тестом через ПодключитьСценарий. + +&ЗначениеПоУмолчанию("main_db") +Перем ИмяБазы Экспорт; + +&ВложенныйДТО("ТестовоеПодключениеКласс") +Перем Подключение Экспорт; + +Процедура ПриСозданииОбъекта() +КонецПроцедуры diff --git "a/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\221\320\260\320\267\320\260\320\224\320\260\320\275\320\275\321\213\321\205\320\241\320\242\320\270\320\277\320\260\320\274\320\270.os" "b/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\221\320\260\320\267\320\260\320\224\320\260\320\275\320\275\321\213\321\205\320\241\320\242\320\270\320\277\320\260\320\274\320\270.os" new file mode 100644 index 0000000..4c5bccd --- /dev/null +++ "b/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\221\320\260\320\267\320\260\320\224\320\260\320\275\320\275\321\213\321\205\320\241\320\242\320\270\320\277\320\260\320\274\320\270.os" @@ -0,0 +1,11 @@ +// DTO с вложенным DTO, оба используют аннотации типов + +&Тип("Строка") +Перем ИмяБазы Экспорт; + +&ВложенныйДТО +Перем Подключение Экспорт; + +Процедура ПриСозданииОбъекта() + Подключение = ЗагрузитьСценарий(ОбъединитьПути(ТекущийСценарий().Каталог, "ТестовоеПодключениеСТипами.os")); +КонецПроцедуры diff --git "a/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\237\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270\320\265.os" "b/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\237\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270\320\265.os" new file mode 100644 index 0000000..40ceb7d --- /dev/null +++ "b/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\237\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270\320\265.os" @@ -0,0 +1,14 @@ +// DTO верхнего уровня: конфигурация приложения с вложенными DTO + +&ЗначениеПоУмолчанию("MyApp") +Перем Название Экспорт; + +&ЗначениеПоУмолчанию("1.0.0") +Перем Версия Экспорт; + +&ВложенныйДТО +Перем БазаДанных Экспорт; + +Процедура ПриСозданииОбъекта() + БазаДанных = ЗагрузитьСценарий(ОбъединитьПути(ТекущийСценарий().Каталог, "ТестовыйДТОБазаДанных.os")); +КонецПроцедуры diff --git "a/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\241\320\234\320\260\321\201\321\201\320\270\320\262\320\276\320\274.os" "b/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\241\320\234\320\260\321\201\321\201\320\270\320\262\320\276\320\274.os" new file mode 100644 index 0000000..49e9140 --- /dev/null +++ "b/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\241\320\234\320\260\321\201\321\201\320\270\320\262\320\276\320\274.os" @@ -0,0 +1,10 @@ +// DTO с массивом вложенных объектов + +&ЗначениеПоУмолчанию("cluster") +Перем Имя Экспорт; + +Перем Узлы Экспорт; + +Процедура ПриСозданииОбъекта() + Узлы = Новый Массив; +КонецПроцедуры diff --git "a/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\241\320\235\320\265\320\270\320\275\320\270\321\206\320\270\320\260\320\273\320\270\320\267\320\270\321\200\320\276\320\262\320\260\320\275\320\275\321\213\320\274\320\222\320\273\320\276\320\266\320\265\320\275\320\275\321\213\320\274.os" "b/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\241\320\235\320\265\320\270\320\275\320\270\321\206\320\270\320\260\320\273\320\270\320\267\320\270\321\200\320\276\320\262\320\260\320\275\320\275\321\213\320\274\320\222\320\273\320\276\320\266\320\265\320\275\320\275\321\213\320\274.os" new file mode 100644 index 0000000..a345b89 --- /dev/null +++ "b/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\241\320\235\320\265\320\270\320\275\320\270\321\206\320\270\320\260\320\273\320\270\320\267\320\270\321\200\320\276\320\262\320\260\320\275\320\275\321\213\320\274\320\222\320\273\320\276\320\266\320\265\320\275\320\275\321\213\320\274.os" @@ -0,0 +1,11 @@ +// DTO с ошибкой в объявлении: свойство помечено как вложенный DTO, +// но ни инициализации в конструкторе, ни имени класса в аннотации нет + +&ЗначениеПоУмолчанию("main_db") +Перем ИмяБазы Экспорт; + +&ВложенныйДТО +Перем Подключение Экспорт; + +Процедура ПриСозданииОбъекта() +КонецПроцедуры diff --git "a/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\241\320\236\320\261\321\217\320\267\320\260\321\202\320\265\320\273\321\214\320\275\321\213\320\274\320\237\320\276\320\273\320\265\320\274.os" "b/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\241\320\236\320\261\321\217\320\267\320\260\321\202\320\265\320\273\321\214\320\275\321\213\320\274\320\237\320\276\320\273\320\265\320\274.os" new file mode 100644 index 0000000..07564fb --- /dev/null +++ "b/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\241\320\236\320\261\321\217\320\267\320\260\321\202\320\265\320\273\321\214\320\275\321\213\320\274\320\237\320\276\320\273\320\265\320\274.os" @@ -0,0 +1,9 @@ +// Тестовый DTO с обязательным полем (без ЗначениеПоУмолчанию) + +&ЗначениеПоУмолчанию("localhost") +Перем АдресСервера Экспорт; + +Перем ОбязательноеПоле Экспорт; + +Процедура ПриСозданииОбъекта() +КонецПроцедуры diff --git "a/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\241\320\241\320\270\320\275\320\276\320\275\320\270\320\274\320\276\320\274.os" "b/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\241\320\241\320\270\320\275\320\276\320\275\320\270\320\274\320\276\320\274.os" new file mode 100644 index 0000000..47a527a --- /dev/null +++ "b/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\241\320\241\320\270\320\275\320\276\320\275\320\270\320\274\320\276\320\274.os" @@ -0,0 +1,8 @@ +// Тестовый DTO с синонимом свойства + +&Синоним("port") +&ЗначениеПоУмолчанию(8080) +Перем Порт Экспорт; + +Процедура ПриСозданииОбъекта() +КонецПроцедуры diff --git "a/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\241\320\242\320\270\320\277\320\260\320\274\320\270.os" "b/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\241\320\242\320\270\320\277\320\260\320\274\320\270.os" new file mode 100644 index 0000000..083a9d7 --- /dev/null +++ "b/tests/fixtures/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\224\320\242\320\236\320\241\320\242\320\270\320\277\320\260\320\274\320\270.os" @@ -0,0 +1,16 @@ +// DTO с аннотациями типов для проверки приведения типов + +&Тип("Число") +Перем Порт Экспорт; + +&Тип("Булево") +Перем Включен Экспорт; + +&Тип("Строка") +Перем Название Экспорт; + +&Тип("Дата") +Перем ДатаЗапуска Экспорт; + +Процедура ПриСозданииОбъекта() +КонецПроцедуры diff --git "a/tests/\320\234\320\265\320\275\320\265\320\264\320\266\320\265\321\200\320\247\321\202\320\265\320\275\320\270\321\217\320\277\320\260\321\200\320\260\320\274\320\265\321\202\321\200\320\276\320\262_test.os" "b/tests/\320\234\320\265\320\275\320\265\320\264\320\266\320\265\321\200\320\247\321\202\320\265\320\275\320\270\321\217\320\277\320\260\321\200\320\260\320\274\320\265\321\202\321\200\320\276\320\262_test.os" index 96f5936..f3f1bf6 100644 --- "a/tests/\320\234\320\265\320\275\320\265\320\264\320\266\320\265\321\200\320\247\321\202\320\265\320\275\320\270\321\217\320\277\320\260\321\200\320\260\320\274\320\265\321\202\321\200\320\276\320\262_test.os" +++ "b/tests/\320\234\320\265\320\275\320\265\320\264\320\266\320\265\321\200\320\247\321\202\320\265\320\275\320\270\321\217\320\277\320\260\321\200\320\260\320\274\320\265\321\202\321\200\320\276\320\262_test.os" @@ -63,12 +63,12 @@ СтруктураПараметров = Новый Структура("version, ПараметрСтрока, ПараметрДата, ПараметрЧисло, ПараметрМассив, ПараметрСтруктура, ПараметрСоответствие", "1.0", "ПростоСтрока", - ТекущаяДата(), + Дата(2017, 1, 1, 12, 30, 45), 10, ПолучитьНовыйМассив("Элемент1, Элемент2, Элемент3"), Новый Структура("Строка, Дата, Число, Массив, Структура, Соответствие", "ПростоСтрока", - ТекущаяДата(), + Дата(2017, 1, 1, 12, 30, 45), 10, ПолучитьНовыйМассив("Элемент1, Элемент2, Элемент3"), Новый Структура("Ключ1, Ключ2", "ЗначениеСтруктуры", "ЗначениеСтруктуры2"), diff --git "a/tests/\320\236\320\277\320\270\321\201\320\260\321\202\320\265\320\273\321\214\320\224\320\242\320\236_test.os" "b/tests/\320\236\320\277\320\270\321\201\320\260\321\202\320\265\320\273\321\214\320\224\320\242\320\236_test.os" new file mode 100644 index 0000000..e42f870 --- /dev/null +++ "b/tests/\320\236\320\277\320\270\321\201\320\260\321\202\320\265\320\273\321\214\320\224\320\242\320\236_test.os" @@ -0,0 +1,750 @@ +#использовать "../" +#Использовать asserts +#Использовать tempfiles + +Перем юТест; +Перем КаталогФикстур; + +Функция ПолучитьСписокТестов(Знач Тестирование) Экспорт + + юТест = Тестирование; + + КаталогФикстур = ОбъединитьПути(ТекущийСценарий().Каталог, "fixtures"); + + ИменаТестов = Новый Массив; + + ИменаТестов.Добавить("ТестДолжен_ОписатьКлассЧитаетАннотацииСвойств"); + ИменаТестов.Добавить("ТестДолжен_ЗарегистрироватьИЗаполнитьДТОИзКонфига"); + ИменаТестов.Добавить("ТестДолжен_ПрименитьЗначенияПоУмолчаниюПриОтсутствииКлюча"); + ИменаТестов.Добавить("ТестДолжен_ВыброситьИсключениеПриОтсутствииОбязательногоПоля"); + ИменаТестов.Добавить("ТестДолжен_ИспользоватьСинонимПриЗаполнении"); + ИменаТестов.Добавить("ТестДолжен_ЗаполнитьВложенныйДТО"); + ИменаТестов.Добавить("ТестДолжен_ЗаполнитьДвухуровневыйДТО"); + ИменаТестов.Добавить("ТестДолжен_ПрименитьУмолчанияВоВложенномДТО"); + ИменаТестов.Добавить("ТестДолжен_СоздатьВложенныйДТОПоИмениКлассаИзАннотации"); + ИменаТестов.Добавить("ТестДолжен_ЗаполнитьВложенныйДТОПереприсвоенныйПослеРегистрации"); + ИменаТестов.Добавить("ТестДолжен_ВыброситьИсключениеЕслиВложенныйДТОНеИнициализирован"); + ИменаТестов.Добавить("ТестДолжен_ОбработатьМассивВоВложенномДТО"); + ИменаТестов.Добавить("ТестДолжен_ПривестиСтрокуКЧислуПоАннотацииТип"); + ИменаТестов.Добавить("ТестДолжен_ПривестиСтрокуКБулевоПоАннотацииТип"); + ИменаТестов.Добавить("ТестДолжен_ПривестиАнглийскиеСтрокиКБулево"); + ИменаТестов.Добавить("ТестДолжен_ВыброситьИсключениеПриНевалидномБулево"); + ИменаТестов.Добавить("ТестДолжен_ПривестиСтрокуКДатеПоАннотацииТип"); + ИменаТестов.Добавить("ТестДолжен_ВыброситьИсключениеПриНевалиднойДате"); + ИменаТестов.Добавить("ТестДолжен_ВыброситьИсключениеПриНевозможностиПриведенияТипа"); + ИменаТестов.Добавить("ТестДолжен_ПривестиТипыВоВложенномДТО"); + ИменаТестов.Добавить("ТестДолжен_НеПриводитьЕслиТипСовпадает"); + ИменаТестов.Добавить("ТестДолжен_ВыброситьИсключениеПриЗанятомПрефиксе"); + ИменаТестов.Добавить("ТестДолжен_СчитатьПрефиксыЗанятымиБезУчетаРегистра"); + ИменаТестов.Добавить("ТестДолжен_ЗаменитьПрефиксПриПовторнойРегистрацииТогоЖеОбъекта"); + ИменаТестов.Добавить("ТестДолжен_ВыброситьИсключениеПриЗаполненииНезарегистрированногоКласса"); + + Возврат ИменаТестов; + +КонецФункции + +Функция ЗагрузитьДТО(Знач ИмяФайла) + Возврат ЗагрузитьСценарий(ОбъединитьПути(КаталогФикстур, ИмяФайла)); +КонецФункции + +// ОписательДТО читает аннотации свойств +Процедура ТестДолжен_ОписатьКлассЧитаетАннотацииСвойств() Экспорт + + // Arrange + ДТО = ЗагрузитьДТО("ТестовыйДТО.os"); + ВременныйФайл = ПолучитьВременныйФайлJSON("{""Тест"": {}}"); + + Менеджер = Новый МенеджерПараметров; + Менеджер.ДобавитьПровайдерПараметров(Новый ПровайдерПараметровJSON()) + .Настройки() + .УстановитьФайлПараметров(ВременныйФайл); + Менеджер.ЗарегистрироватьКлассПараметров(ДТО, "Тест"); + + // Act + Менеджер.Прочитать(); + Менеджер.ЗаполнитьОбъектПараметров(ДТО); + + // Assert + Ожидаем.Что(ДТО.АдресСервера, "Аннотация ЗначениеПоУмолчанию должна быть прочитана для АдресСервера").Равно("localhost"); + Ожидаем.Что(ДТО.ПортСервера, "Аннотация ЗначениеПоУмолчанию должна быть прочитана для ПортСервера").Равно(8080); + + УдалитьФайлы(ВременныйФайл); + +КонецПроцедуры + +// Регистрация и заполнение DTO из конфига +Процедура ТестДолжен_ЗарегистрироватьИЗаполнитьДТОИзКонфига() Экспорт + + ДТО = ЗагрузитьДТО("ТестовыйДТО.os"); + + ВременныйФайл = ПолучитьВременныйФайлJSON( + "{""Префикс"": {""АдресСервера"": ""prod-server"", ""ПортСервера"": 3306}}" + ); + + Менеджер = Новый МенеджерПараметров; + Менеджер.ДобавитьПровайдерПараметров(Новый ПровайдерПараметровJSON()) + .Настройки() + .УстановитьФайлПараметров(ВременныйФайл); + Менеджер.ЗарегистрироватьКлассПараметров(ДТО, "Префикс"); + Менеджер.Прочитать(); + Менеджер.ЗаполнитьОбъектПараметров(ДТО); + + Ожидаем.Что(ДТО.АдресСервера, "АдресСервера должен быть из конфига").Равно("prod-server"); + Ожидаем.Что(ДТО.ПортСервера, "ПортСервера должен быть из конфига").Равно(3306); + + УдалитьФайлы(ВременныйФайл); + +КонецПроцедуры + +// Значения по умолчанию при отсутствии ключа +Процедура ТестДолжен_ПрименитьЗначенияПоУмолчаниюПриОтсутствииКлюча() Экспорт + + ДТО = ЗагрузитьДТО("ТестовыйДТО.os"); + + ВременныйФайл = ПолучитьВременныйФайлJSON( + "{""Префикс"": {""АдресСервера"": ""prod-server""}}" + ); + + Менеджер = Новый МенеджерПараметров; + Менеджер.ДобавитьПровайдерПараметров(Новый ПровайдерПараметровJSON()) + .Настройки() + .УстановитьФайлПараметров(ВременныйФайл); + Менеджер.ЗарегистрироватьКлассПараметров(ДТО, "Префикс"); + Менеджер.Прочитать(); + Менеджер.ЗаполнитьОбъектПараметров(ДТО); + + Ожидаем.Что(ДТО.АдресСервера, "АдресСервера должен быть из конфига").Равно("prod-server"); + Ожидаем.Что(ДТО.ПортСервера, "ПортСервера должен быть дефолтным").Равно(8080); + + УдалитьФайлы(ВременныйФайл); + +КонецПроцедуры + +// Обязательное поле без значения - исключение +Процедура ТестДолжен_ВыброситьИсключениеПриОтсутствииОбязательногоПоля() Экспорт + + ДТО = ЗагрузитьДТО("ТестовыйДТОСОбязательнымПолем.os"); + + ВременныйФайл = ПолучитьВременныйФайлJSON( + "{""Префикс"": {""АдресСервера"": ""prod-server""}}" + ); + + Менеджер = Новый МенеджерПараметров; + Менеджер.ДобавитьПровайдерПараметров(Новый ПровайдерПараметровJSON()) + .Настройки() + .УстановитьФайлПараметров(ВременныйФайл); + Менеджер.ЗарегистрироватьКлассПараметров(ДТО, "Префикс"); + Менеджер.Прочитать(); + + Попытка + Менеджер.ЗаполнитьОбъектПараметров(ДТО); + Ожидаем.Что(Ложь, "Ожидалось исключение для обязательного поля").Равно(Истина); + Исключение + Ожидаем.Что(ОписаниеОшибки()).Содержит("ОбязательноеПоле"); + КонецПопытки; + + УдалитьФайлы(ВременныйФайл); + +КонецПроцедуры + +// Синоним при заполнении +Процедура ТестДолжен_ИспользоватьСинонимПриЗаполнении() Экспорт + + ДТО = ЗагрузитьДТО("ТестовыйДТОССинонимом.os"); + + ВременныйФайл = ПолучитьВременныйФайлJSON( + "{""Префикс"": {""port"": 3306}}" + ); + + Менеджер = Новый МенеджерПараметров; + Менеджер.ДобавитьПровайдерПараметров(Новый ПровайдерПараметровJSON()) + .Настройки() + .УстановитьФайлПараметров(ВременныйФайл); + Менеджер.ЗарегистрироватьКлассПараметров(ДТО, "Префикс"); + Менеджер.Прочитать(); + Менеджер.ЗаполнитьОбъектПараметров(ДТО); + + Ожидаем.Что(ДТО.Порт, "Порт должен быть заполнен из конфига по синониму port").Равно(3306); + + УдалитьФайлы(ВременныйФайл); + +КонецПроцедуры + +// Вложенный DTO - БазаДанных.Подключение +Процедура ТестДолжен_ЗаполнитьВложенныйДТО() Экспорт + + // Arrange + ДТО = ЗагрузитьДТО("ТестовыйДТОБазаДанных.os"); + ВременныйФайл = ПолучитьВременныйФайлJSON( + "{""БД"": {""ИмяБазы"": ""test_db"", ""Подключение"": {""Хост"": ""db-server"", ""Порт"": 3306}}}" + ); + + Менеджер = Новый МенеджерПараметров; + Менеджер.ДобавитьПровайдерПараметров(Новый ПровайдерПараметровJSON()) + .Настройки() + .УстановитьФайлПараметров(ВременныйФайл); + Менеджер.ЗарегистрироватьКлассПараметров(ДТО, "БД"); + + // Act + Менеджер.Прочитать(); + Менеджер.ЗаполнитьОбъектПараметров(ДТО); + + // Assert + Ожидаем.Что(ДТО.ИмяБазы, "ИмяБазы должно быть из конфига").Равно("test_db"); + Ожидаем.Что(ДТО.Подключение.Хост, "Вложенный Хост должен быть заполнен из конфига").Равно("db-server"); + Ожидаем.Что(ДТО.Подключение.Порт, "Вложенный Порт должен быть заполнен из конфига").Равно(3306); + + УдалитьФайлы(ВременныйФайл); + +КонецПроцедуры + +// Трёхуровневый DTO - Приложение.БазаДанных.Подключение +Процедура ТестДолжен_ЗаполнитьДвухуровневыйДТО() Экспорт + + // Arrange + ДТО = ЗагрузитьДТО("ТестовыйДТОПриложение.os"); + ВременныйФайл = ПолучитьВременныйФайлJSON( + "{""Приложение"": {""Название"": ""SuperApp"", ""Версия"": ""2.0.0"", ""БазаДанных"": {""ИмяБазы"": ""prod_db"", ""Подключение"": {""Хост"": ""prod-host"", ""Порт"": 5432}}}}" + ); + + Менеджер = Новый МенеджерПараметров; + Менеджер.ДобавитьПровайдерПараметров(Новый ПровайдерПараметровJSON()) + .Настройки() + .УстановитьФайлПараметров(ВременныйФайл); + Менеджер.ЗарегистрироватьКлассПараметров(ДТО, "Приложение"); + + // Act + Менеджер.Прочитать(); + Менеджер.ЗаполнитьОбъектПараметров(ДТО); + + // Assert + Ожидаем.Что(ДТО.Название, "Название должно быть из конфига").Равно("SuperApp"); + Ожидаем.Что(ДТО.Версия, "Версия должна быть из конфига").Равно("2.0.0"); + Ожидаем.Что(ДТО.БазаДанных.ИмяБазы, "Вложенное ИмяБазы должно быть из конфига").Равно("prod_db"); + Ожидаем.Что(ДТО.БазаДанных.Подключение.Хост, "Глубоко вложенный Хост должен быть из конфига").Равно("prod-host"); + Ожидаем.Что(ДТО.БазаДанных.Подключение.Порт, "Глубоко вложенный Порт должен быть из конфига").Равно(5432); + + УдалитьФайлы(ВременныйФайл); + +КонецПроцедуры + +// Вложенный DTO - умолчания при отсутствии ключей во вложенной структуре +Процедура ТестДолжен_ПрименитьУмолчанияВоВложенномДТО() Экспорт + + // Arrange + ДТО = ЗагрузитьДТО("ТестовыйДТОБазаДанных.os"); + ВременныйФайл = ПолучитьВременныйФайлJSON( + "{""БД"": {""ИмяБазы"": ""custom_db""}}" + ); + + Менеджер = Новый МенеджерПараметров; + Менеджер.ДобавитьПровайдерПараметров(Новый ПровайдерПараметровJSON()) + .Настройки() + .УстановитьФайлПараметров(ВременныйФайл); + Менеджер.ЗарегистрироватьКлассПараметров(ДТО, "БД"); + + // Act + Менеджер.Прочитать(); + Менеджер.ЗаполнитьОбъектПараметров(ДТО); + + // Assert + Ожидаем.Что(ДТО.ИмяБазы, "ИмяБазы должно быть из конфига").Равно("custom_db"); + Ожидаем.Что(ДТО.Подключение.Хост, "Вложенный Хост должен быть по умолчанию").Равно("localhost"); + Ожидаем.Что(ДТО.Подключение.Порт, "Вложенный Порт должен быть по умолчанию").Равно(5432); + + УдалитьФайлы(ВременныйФайл); + +КонецПроцедуры + +// Вложенный DTO создаётся по имени класса из параметра аннотации &ВложенныйДТО, +// когда свойство не инициализировано в конструкторе +Процедура ТестДолжен_СоздатьВложенныйДТОПоИмениКлассаИзАннотации() Экспорт + + // Arrange + // имя класса, на которое ссылается аннотация в фикстуре, должно быть доступно для Новый() + ПодключитьСценарий(ОбъединитьПути(КаталогФикстур, "ТестовоеПодключение.os"), "ТестовоеПодключениеКласс"); + + ДТО = ЗагрузитьДТО("ТестовыйДТОБазаДанныхАннотация.os"); + Ожидаем.Что(ДТО.Подключение, "До регистрации вложенный объект не создан").Равно(Неопределено); + + ВременныйФайл = ПолучитьВременныйФайлJSON( + "{""БД"": {""ИмяБазы"": ""test_db"", ""Подключение"": {""Хост"": ""db-server"", ""Порт"": 3306}}}" + ); + + Менеджер = Новый МенеджерПараметров; + Менеджер.ДобавитьПровайдерПараметров(Новый ПровайдерПараметровJSON()) + .Настройки() + .УстановитьФайлПараметров(ВременныйФайл); + + // Act + Менеджер.ЗарегистрироватьКлассПараметров(ДТО, "БД"); + + // Assert: объект создан описателем по имени класса из аннотации + Ожидаем.Что(Строка(ТипЗнч(ДТО.Подключение)), "Вложенный объект создан по имени класса из аннотации") + .Равно("ТестовоеПодключениеКласс"); + + Менеджер.Прочитать(); + Менеджер.ЗаполнитьОбъектПараметров(ДТО); + + Ожидаем.Что(ДТО.ИмяБазы, "ИмяБазы должно быть из конфига").Равно("test_db"); + Ожидаем.Что(ДТО.Подключение.Хост, "Вложенный Хост должен быть заполнен из конфига").Равно("db-server"); + Ожидаем.Что(ДТО.Подключение.Порт, "Вложенный Порт должен быть заполнен из конфига").Равно(3306); + + УдалитьФайлы(ВременныйФайл); + +КонецПроцедуры + +// Заполняется тот экземпляр вложенного DTO, который лежит в свойстве +// на момент заполнения, а не тот, что был там при регистрации +Процедура ТестДолжен_ЗаполнитьВложенныйДТОПереприсвоенныйПослеРегистрации() Экспорт + + // Arrange + ДТО = ЗагрузитьДТО("ТестовыйДТОБазаДанных.os"); + ВременныйФайл = ПолучитьВременныйФайлJSON( + "{""БД"": {""ИмяБазы"": ""test_db"", ""Подключение"": {""Хост"": ""db-server"", ""Порт"": 3306}}}" + ); + + Менеджер = Новый МенеджерПараметров; + Менеджер.ДобавитьПровайдерПараметров(Новый ПровайдерПараметровJSON()) + .Настройки() + .УстановитьФайлПараметров(ВременныйФайл); + Менеджер.ЗарегистрироватьКлассПараметров(ДТО, "БД"); + + // Act: подменяем вложенный объект уже после регистрации + НовоеПодключение = ЗагрузитьДТО("ТестовоеПодключение.os"); + ДТО.Подключение = НовоеПодключение; + + Менеджер.Прочитать(); + Менеджер.ЗаполнитьОбъектПараметров(ДТО); + + // Assert: заполнен новый экземпляр, а не захваченный при регистрации + Ожидаем.Что(НовоеПодключение.Хост, "Заполнен должен быть текущий экземпляр вложенного DTO").Равно("db-server"); + Ожидаем.Что(НовоеПодключение.Порт, "Заполнен должен быть текущий экземпляр вложенного DTO").Равно(3306); + + УдалитьФайлы(ВременныйФайл); + +КонецПроцедуры + +// Регистрация падает, если поле помечено как вложенный DTO, +// но объекта нет и класс в аннотации не указан +Процедура ТестДолжен_ВыброситьИсключениеЕслиВложенныйДТОНеИнициализирован() Экспорт + + ДТО = ЗагрузитьДТО("ТестовыйДТОСНеинициализированнымВложенным.os"); + + ВременныйФайл = ПолучитьВременныйФайлJSON( + "{""БД"": {""ИмяБазы"": ""test_db"", ""Подключение"": {""Хост"": ""h"", ""Порт"": 1}}}" + ); + + Менеджер = Новый МенеджерПараметров; + Менеджер.ДобавитьПровайдерПараметров(Новый ПровайдерПараметровJSON()) + .Настройки() + .УстановитьФайлПараметров(ВременныйФайл); + + Попытка + Менеджер.ЗарегистрироватьКлассПараметров(ДТО, "БД"); + Ожидаем.Что(Ложь, "Ожидалось исключение при описании неинициализированного вложенного DTO").Равно(Истина); + Исключение + Ожидаем.Что(ОписаниеОшибки()).Содержит("Подключение"); + КонецПопытки; + + УдалитьФайлы(ВременныйФайл); + +КонецПроцедуры + +// DTO с массивом во вложенной структуре +Процедура ТестДолжен_ОбработатьМассивВоВложенномДТО() Экспорт + + // Arrange + ДТО = ЗагрузитьДТО("ТестовыйДТОСМассивом.os"); + ВременныйФайл = ПолучитьВременныйФайлJSON( + "{""Кластер"": {""Имя"": ""prod-cluster"", ""Узлы"": [""node1"", ""node2"", ""node3""]}}" + ); + + Менеджер = Новый МенеджерПараметров; + Менеджер.ДобавитьПровайдерПараметров(Новый ПровайдерПараметровJSON()) + .Настройки() + .УстановитьФайлПараметров(ВременныйФайл); + Менеджер.ЗарегистрироватьКлассПараметров(ДТО, "Кластер"); + + // Act + Менеджер.Прочитать(); + Менеджер.ЗаполнитьОбъектПараметров(ДТО); + + // Assert + Ожидаем.Что(ДТО.Имя, "Имя кластера должно быть из конфига").Равно("prod-cluster"); + Ожидаем.Что(ДТО.Узлы.Количество(), "Должно быть 3 узла").Равно(3); + Ожидаем.Что(ДТО.Узлы[0], "Первый узел").Равно("node1"); + Ожидаем.Что(ДТО.Узлы[1], "Второй узел").Равно("node2"); + Ожидаем.Что(ДТО.Узлы[2], "Третий узел").Равно("node3"); + + УдалитьФайлы(ВременныйФайл); + +КонецПроцедуры + +// Приведение строки к числу по &Тип("Число") +Процедура ТестДолжен_ПривестиСтрокуКЧислуПоАннотацииТип() Экспорт + + ДТО = ЗагрузитьДТО("ТестовыйДТОСТипами.os"); + + // Имитируем ситуацию, когда из ENV/INI приходят строки + ВременныйФайл = ПолучитьВременныйФайлJSON( + "{""cfg"": {""Порт"": ""8080"", ""Включен"": ""true"", ""Название"": 42, ""ДатаЗапуска"": ""2025-01-15T00:00:00""}}" + ); + + Менеджер = Новый МенеджерПараметров; + Менеджер.ДобавитьПровайдерПараметров(Новый ПровайдерПараметровJSON()) + .Настройки() + .УстановитьФайлПараметров(ВременныйФайл); + Менеджер.ЗарегистрироватьКлассПараметров(ДТО, "cfg"); + Менеджер.Прочитать(); + Менеджер.ЗаполнитьОбъектПараметров(ДТО); + + Ожидаем.Что(ТипЗнч(ДТО.Порт), "Порт должен быть числом").Равно(Тип("Число")); + Ожидаем.Что(ДТО.Порт, "Порт должен быть 8080").Равно(8080); + + УдалитьФайлы(ВременныйФайл); + +КонецПроцедуры + +// Приведение строки к булево по &Тип("Булево") +Процедура ТестДолжен_ПривестиСтрокуКБулевоПоАннотацииТип() Экспорт + + ДТО = ЗагрузитьДТО("ТестовыйДТОСТипами.os"); + + ВременныйФайл = ПолучитьВременныйФайлJSON( + "{""cfg"": {""Порт"": ""3306"", ""Включен"": ""Истина"", ""Название"": ""test"", ""ДатаЗапуска"": ""2025-06-01T00:00:00""}}" + ); + + Менеджер = Новый МенеджерПараметров; + Менеджер.ДобавитьПровайдерПараметров(Новый ПровайдерПараметровJSON()) + .Настройки() + .УстановитьФайлПараметров(ВременныйФайл); + Менеджер.ЗарегистрироватьКлассПараметров(ДТО, "cfg"); + Менеджер.Прочитать(); + Менеджер.ЗаполнитьОбъектПараметров(ДТО); + + Ожидаем.Что(ТипЗнч(ДТО.Включен), "Включен должен быть булево").Равно(Тип("Булево")); + Ожидаем.Что(ДТО.Включен, "Включен должен быть Истина").Равно(Истина); + + УдалитьФайлы(ВременныйФайл); + +КонецПроцедуры + +// Приведение английских строк true/false к булево +Процедура ТестДолжен_ПривестиАнглийскиеСтрокиКБулево() Экспорт + + ДТО = ЗагрузитьДТО("ТестовыйДТОСТипами.os"); + + ВременныйФайл = ПолучитьВременныйФайлJSON( + "{""cfg"": {""Порт"": ""1"", ""Включен"": ""true"", ""Название"": ""test"", ""ДатаЗапуска"": ""2025-01-01T00:00:00""}}" + ); + + Менеджер = Новый МенеджерПараметров; + Менеджер.ДобавитьПровайдерПараметров(Новый ПровайдерПараметровJSON()) + .Настройки() + .УстановитьФайлПараметров(ВременныйФайл); + Менеджер.ЗарегистрироватьКлассПараметров(ДТО, "cfg"); + Менеджер.Прочитать(); + Менеджер.ЗаполнитьОбъектПараметров(ДТО); + + Ожидаем.Что(ТипЗнч(ДТО.Включен), "Включен должен быть булево").Равно(Тип("Булево")); + Ожидаем.Что(ДТО.Включен, "Строка ""true"" должна стать Истина").Равно(Истина); + + УдалитьФайлы(ВременныйФайл); + + // та же проверка для "false" + ДТО = ЗагрузитьДТО("ТестовыйДТОСТипами.os"); + + ВременныйФайл = ПолучитьВременныйФайлJSON( + "{""cfg"": {""Порт"": ""1"", ""Включен"": ""false"", ""Название"": ""test"", ""ДатаЗапуска"": ""2025-01-01T00:00:00""}}" + ); + + Менеджер = Новый МенеджерПараметров; + Менеджер.ДобавитьПровайдерПараметров(Новый ПровайдерПараметровJSON()) + .Настройки() + .УстановитьФайлПараметров(ВременныйФайл); + Менеджер.ЗарегистрироватьКлассПараметров(ДТО, "cfg"); + Менеджер.Прочитать(); + Менеджер.ЗаполнитьОбъектПараметров(ДТО); + + Ожидаем.Что(ТипЗнч(ДТО.Включен), "Включен должен быть булево").Равно(Тип("Булево")); + Ожидаем.Что(ДТО.Включен, "Строка ""false"" должна стать Ложь").Равно(Ложь); + + УдалитьФайлы(ВременныйФайл); + +КонецПроцедуры + +// Нераспознанная строка для булево вызывает исключение +Процедура ТестДолжен_ВыброситьИсключениеПриНевалидномБулево() Экспорт + + ДТО = ЗагрузитьДТО("ТестовыйДТОСТипами.os"); + + ВременныйФайл = ПолучитьВременныйФайлJSON( + "{""cfg"": {""Порт"": ""1"", ""Включен"": ""maybe"", ""Название"": ""test"", ""ДатаЗапуска"": ""2025-01-01T00:00:00""}}" + ); + + Менеджер = Новый МенеджерПараметров; + Менеджер.ДобавитьПровайдерПараметров(Новый ПровайдерПараметровJSON()) + .Настройки() + .УстановитьФайлПараметров(ВременныйФайл); + Менеджер.ЗарегистрироватьКлассПараметров(ДТО, "cfg"); + Менеджер.Прочитать(); + + Попытка + Менеджер.ЗаполнитьОбъектПараметров(ДТО); + Ожидаем.Что(Ложь, "Ожидалось исключение для невалидного булева значения").Равно(Истина); + Исключение + Ожидаем.Что(ОписаниеОшибки()).Содержит("Включен"); + КонецПопытки; + + УдалитьФайлы(ВременныйФайл); + + // перечисление нескольких допустимых значений через запятую не является допустимым значением + ДТО = ЗагрузитьДТО("ТестовыйДТОСТипами.os"); + + ВременныйФайл = ПолучитьВременныйФайлJSON( + "{""cfg"": {""Порт"": ""1"", ""Включен"": ""1,TRUE"", ""Название"": ""t"", ""ДатаЗапуска"": ""2025-01-01T00:00:00""}}" + ); + + Менеджер = Новый МенеджерПараметров; + Менеджер.ДобавитьПровайдерПараметров(Новый ПровайдерПараметровJSON()) + .Настройки() + .УстановитьФайлПараметров(ВременныйФайл); + Менеджер.ЗарегистрироватьКлассПараметров(ДТО, "cfg"); + Менеджер.Прочитать(); + + Попытка + Менеджер.ЗаполнитьОбъектПараметров(ДТО); + Ожидаем.Что(Ложь, "Ожидалось исключение для значения ""1,TRUE""").Равно(Истина); + Исключение + Ожидаем.Что(ОписаниеОшибки()).Содержит("Включен"); + КонецПопытки; + + УдалитьФайлы(ВременныйФайл); + +КонецПроцедуры + +// Приведение строки в формате ISO к дате по &Тип("Дата") +Процедура ТестДолжен_ПривестиСтрокуКДатеПоАннотацииТип() Экспорт + + ДТО = ЗагрузитьДТО("ТестовыйДТОСТипами.os"); + + ВременныйФайл = ПолучитьВременныйФайлJSON( + "{""cfg"": {""Порт"": ""1"", ""Включен"": ""true"", ""Название"": ""t"", ""ДатаЗапуска"": ""2025-01-15T13:45:30""}}" + ); + + Менеджер = Новый МенеджерПараметров; + Менеджер.ДобавитьПровайдерПараметров(Новый ПровайдерПараметровJSON()) + .Настройки() + .УстановитьФайлПараметров(ВременныйФайл); + Менеджер.ЗарегистрироватьКлассПараметров(ДТО, "cfg"); + Менеджер.Прочитать(); + Менеджер.ЗаполнитьОбъектПараметров(ДТО); + + Ожидаем.Что(ТипЗнч(ДТО.ДатаЗапуска), "ДатаЗапуска должна быть датой").Равно(Тип("Дата")); + Ожидаем.Что(ДТО.ДатаЗапуска, "Строка должна разобраться целиком, вместе со временем") + .Равно(Дата(2025, 1, 15, 13, 45, 30)); + + УдалитьФайлы(ВременныйФайл); + +КонецПроцедуры + +// Нераспознанная дата вызывает исключение +Процедура ТестДолжен_ВыброситьИсключениеПриНевалиднойДате() Экспорт + + ДТО = ЗагрузитьДТО("ТестовыйДТОСТипами.os"); + + ВременныйФайл = ПолучитьВременныйФайлJSON( + "{""cfg"": {""Порт"": ""1"", ""Включен"": ""true"", ""Название"": ""t"", ""ДатаЗапуска"": ""вчера""}}" + ); + + Менеджер = Новый МенеджерПараметров; + Менеджер.ДобавитьПровайдерПараметров(Новый ПровайдерПараметровJSON()) + .Настройки() + .УстановитьФайлПараметров(ВременныйФайл); + Менеджер.ЗарегистрироватьКлассПараметров(ДТО, "cfg"); + Менеджер.Прочитать(); + + Попытка + Менеджер.ЗаполнитьОбъектПараметров(ДТО); + Ожидаем.Что(Ложь, "Ожидалось исключение для невалидной даты").Равно(Истина); + Исключение + Ожидаем.Что(ОписаниеОшибки()).Содержит("ДатаЗапуска"); + КонецПопытки; + + УдалитьФайлы(ВременныйФайл); + +КонецПроцедуры + +// Ошибка при невозможности приведения типа +Процедура ТестДолжен_ВыброситьИсключениеПриНевозможностиПриведенияТипа() Экспорт + + ДТО = ЗагрузитьДТО("ТестовыйДТОСТипами.os"); + + ВременныйФайл = ПолучитьВременныйФайлJSON( + "{""cfg"": {""Порт"": ""not_a_number"", ""Включен"": ""false"", ""Название"": ""test"", ""ДатаЗапуска"": ""2025-01-01T00:00:00""}}" + ); + + Менеджер = Новый МенеджерПараметров; + Менеджер.ДобавитьПровайдерПараметров(Новый ПровайдерПараметровJSON()) + .Настройки() + .УстановитьФайлПараметров(ВременныйФайл); + Менеджер.ЗарегистрироватьКлассПараметров(ДТО, "cfg"); + Менеджер.Прочитать(); + + Попытка + Менеджер.ЗаполнитьОбъектПараметров(ДТО); + Ожидаем.Что(Ложь, "Ожидалось исключение приведения типа").Равно(Истина); + Исключение + Ожидаем.Что(ОписаниеОшибки()).Содержит("Порт"); + КонецПопытки; + + УдалитьФайлы(ВременныйФайл); + +КонецПроцедуры + +// Приведение типов во вложенном ДТО +Процедура ТестДолжен_ПривестиТипыВоВложенномДТО() Экспорт + + ДТО = ЗагрузитьДТО("ТестовыйДТОБазаДанныхСТипами.os"); + + // Все значения как строки (имитация ENV) + ВременныйФайл = ПолучитьВременныйФайлJSON( + "{""db"": {""ИмяБазы"": ""test_db"", ""Подключение"": {""Хост"": ""db-host"", ""Порт"": ""5432"", ""SSL"": ""true""}}}" + ); + + Менеджер = Новый МенеджерПараметров; + Менеджер.ДобавитьПровайдерПараметров(Новый ПровайдерПараметровJSON()) + .Настройки() + .УстановитьФайлПараметров(ВременныйФайл); + Менеджер.ЗарегистрироватьКлассПараметров(ДТО, "db"); + Менеджер.Прочитать(); + Менеджер.ЗаполнитьОбъектПараметров(ДТО); + + Ожидаем.Что(ТипЗнч(ДТО.ИмяБазы), "ИмяБазы должно быть строкой").Равно(Тип("Строка")); + Ожидаем.Что(ДТО.Подключение.Хост, "Вложенный Хост должен быть строкой").Равно("db-host"); + Ожидаем.Что(ТипЗнч(ДТО.Подключение.Порт), "Вложенный Порт должен стать числом").Равно(Тип("Число")); + Ожидаем.Что(ДТО.Подключение.Порт, "Вложенный Порт должен быть 5432").Равно(5432); + Ожидаем.Что(ТипЗнч(ДТО.Подключение.SSL), "Вложенный SSL должен стать булево").Равно(Тип("Булево")); + Ожидаем.Что(ДТО.Подключение.SSL, "Вложенный SSL должен быть Истина").Равно(Истина); + + УдалитьФайлы(ВременныйФайл); + +КонецПроцедуры + +// Не приводить если тип уже совпадает +Процедура ТестДолжен_НеПриводитьЕслиТипСовпадает() Экспорт + + ДТО = ЗагрузитьДТО("ТестовыйДТОСТипами.os"); + + // JSON провайдер вернёт число как число - приведение не нужно + ВременныйФайл = ПолучитьВременныйФайлJSON( + "{""cfg"": {""Порт"": 8080, ""Включен"": true, ""Название"": ""test"", ""ДатаЗапуска"": ""2025-01-01T00:00:00""}}" + ); + + Менеджер = Новый МенеджерПараметров; + Менеджер.ДобавитьПровайдерПараметров(Новый ПровайдерПараметровJSON()) + .Настройки() + .УстановитьФайлПараметров(ВременныйФайл); + Менеджер.ЗарегистрироватьКлассПараметров(ДТО, "cfg"); + Менеджер.Прочитать(); + Менеджер.ЗаполнитьОбъектПараметров(ДТО); + + Ожидаем.Что(ТипЗнч(ДТО.Порт), "Порт должен остаться числом").Равно(Тип("Число")); + Ожидаем.Что(ДТО.Порт, "Порт должен быть 8080").Равно(8080); + Ожидаем.Что(ТипЗнч(ДТО.Включен), "Включен должен остаться булево").Равно(Тип("Булево")); + Ожидаем.Что(ДТО.Включен, "Включен должен быть true").Равно(Истина); + + УдалитьФайлы(ВременныйФайл); + +КонецПроцедуры + +// Два разных класса не могут занять один префикс: +// какой из них выиграл бы при заполнении, определить нельзя +Процедура ТестДолжен_ВыброситьИсключениеПриЗанятомПрефиксе() Экспорт + + ПервыйДТО = ЗагрузитьДТО("ТестовыйДТО.os"); + ВторойДТО = ЗагрузитьДТО("ТестовыйДТОССинонимом.os"); + + Менеджер = Новый МенеджерПараметров; + Менеджер.ЗарегистрироватьКлассПараметров(ПервыйДТО, "Префикс"); + + Попытка + Менеджер.ЗарегистрироватьКлассПараметров(ВторойДТО, "Префикс"); + Ожидаем.Что(Ложь, "Ожидалось исключение при регистрации на занятый префикс").Равно(Истина); + Исключение + Ожидаем.Что(ОписаниеОшибки()).Содержит("Префикс"); + КонецПопытки; + +КонецПроцедуры + +// Индекс параметров регистронезависим, поэтому префиксы, +// отличающиеся только регистром, считаются одним и тем же +Процедура ТестДолжен_СчитатьПрефиксыЗанятымиБезУчетаРегистра() Экспорт + + ПервыйДТО = ЗагрузитьДТО("ТестовыйДТО.os"); + ВторойДТО = ЗагрузитьДТО("ТестовыйДТОССинонимом.os"); + + Менеджер = Новый МенеджерПараметров; + Менеджер.ЗарегистрироватьКлассПараметров(ПервыйДТО, "Префикс"); + + Попытка + Менеджер.ЗарегистрироватьКлассПараметров(ВторойДТО, "ПРЕФИКС"); + Ожидаем.Что(Ложь, "Ожидалось исключение для префикса, отличающегося регистром").Равно(Истина); + Исключение + Ожидаем.Что(ОписаниеОшибки()).Содержит("ПРЕФИКС"); + КонецПопытки; + +КонецПроцедуры + +// Повторная регистрация того же объекта заменяет прежнюю запись, +// заполнение идёт по префиксу из последней регистрации +Процедура ТестДолжен_ЗаменитьПрефиксПриПовторнойРегистрацииТогоЖеОбъекта() Экспорт + + ДТО = ЗагрузитьДТО("ТестовыйДТО.os"); + + ВременныйФайл = ПолучитьВременныйФайлJSON( + "{""Старый"": {""АдресСервера"": ""old-server""}, ""Новый"": {""АдресСервера"": ""new-server""}}" + ); + + Менеджер = Новый МенеджерПараметров; + Менеджер.ДобавитьПровайдерПараметров(Новый ПровайдерПараметровJSON()) + .Настройки() + .УстановитьФайлПараметров(ВременныйФайл); + + Менеджер.ЗарегистрироватьКлассПараметров(ДТО, "Старый"); + Менеджер.ЗарегистрироватьКлассПараметров(ДТО, "Новый"); + Менеджер.Прочитать(); + Менеджер.ЗаполнитьОбъектПараметров(ДТО); + + Ожидаем.Что(ДТО.АдресСервера, "Заполнение должно идти по префиксу последней регистрации").Равно("new-server"); + + УдалитьФайлы(ВременныйФайл); + +КонецПроцедуры + +// Заполнение возможно только для зарегистрированного класса +Процедура ТестДолжен_ВыброситьИсключениеПриЗаполненииНезарегистрированногоКласса() Экспорт + + ДТО = ЗагрузитьДТО("ТестовыйДТО.os"); + + Менеджер = Новый МенеджерПараметров; + + Попытка + Менеджер.ЗаполнитьОбъектПараметров(ДТО); + Ожидаем.Что(Ложь, "Ожидалось исключение для незарегистрированного класса").Равно(Истина); + Исключение + Ожидаем.Что(ОписаниеОшибки()).Содержит("ЗарегистрироватьКлассПараметров"); + КонецПопытки; + +КонецПроцедуры + +Функция ПолучитьВременныйФайлJSON(Знач СодержимоеJSON) + + ВременныйФайл = ПолучитьИмяВременногоФайла("json"); + ЗаписьТекста = Новый ЗаписьТекста(ВременныйФайл, "UTF-8"); + ЗаписьТекста.Записать(СодержимоеJSON); + ЗаписьТекста.Закрыть(); + Возврат ВременныйФайл; + +КонецФункции