From 45faad37f89a13736f89bc2f60ce04f27f70a039 Mon Sep 17 00:00:00 2001 From: Stepan Date: Mon, 6 May 2024 12:55:42 +0300 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D1=8B=20=D1=82=D0=B5=D1=81=D1=82=D1=8B=20YaxUnit=20?= =?UTF-8?q?=D0=B8=20Vanessa=20(#51)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Добавлены тесты YaxUnit и Vanessa Automation, настроены шаги сборки, добавлено руководство по добавлению юнит-тестов --- .gitignore | 6 +- README.md | 6 + docs/РуководствоПоНаписаниюТестовYAxUnit.md | 86 + features/Проверка пометки на удаление.feature | 29 + .../Создание элемента справочника.feature | 30 + jobConfiguration.json | 46 +- sonar-project.properties | 4 +- .../Catalogs/__ИнтегрируемыеСистемы.xml | 0 .../Ext/ManagerModule.bsl | 0 .../Forms/ФормаСписка.xml | 0 .../Forms/ФормаСписка/Ext/Form.xml | 0 .../Forms/ФормаСписка/Ext/Form/Module.bsl | 0 .../Forms/ФормаЭлемента.xml | 0 .../Forms/ФормаЭлемента/Ext/Form.xml | 0 src/{ => cf}/Catalogs/__ИсторияИнтеграции.xml | 0 .../__ИсторияИнтеграции/Ext/ManagerModule.bsl | 0 .../__ИсторияИнтеграции/Ext/ObjectModule.bsl | 0 .../__ИсторияИнтеграции/Forms/ФормаСписка.xml | 0 .../Forms/ФормаСписка/Ext/Form.xml | 0 .../Forms/ФормаСписка/Ext/Form/Module.bsl | 0 .../Forms/ФормаЭлемента.xml | 0 .../Forms/ФормаЭлемента/Ext/Form.xml | 0 .../Forms/ФормаЭлемента/Ext/Form/Module.bsl | 0 src/{ => cf}/Catalogs/__МетодыИнтеграции.xml | 0 .../__МетодыИнтеграции/Ext/ManagerModule.bsl | 0 .../__МетодыИнтеграции/Forms/ФормаСписка.xml | 0 .../Forms/ФормаСписка/Ext/Form.xml | 0 .../Forms/ФормаСписка/Ext/Form/Module.bsl | 0 .../Forms/ФормаЭлемента.xml | 0 .../Forms/ФормаЭлемента/Ext/Form.xml | 0 .../Catalogs/__НастройкиИнтеграции.xml | 0 .../Ext/ManagerModule.bsl | 0 .../Forms/ФормаСписка.xml | 0 .../Forms/ФормаСписка/Ext/Form.xml | 0 .../Forms/ФормаСписка/Ext/Form/Module.bsl | 0 .../Forms/ФормаЭлемента.xml | 0 .../Forms/ФормаЭлемента/Ext/Form.xml | 0 .../Forms/ФормаЭлемента/Ext/Form/Module.bsl | 0 .../Catalogs/__НастройкиОтбораОбъектов.xml | 0 .../Ext/ManagerModule.bsl | 0 .../Forms/ФормаВыбораОбъектаМетаданных.xml | 0 .../Forms/ФормаВыбораОбъектаМетаданных/Ext/Form.xml | 0 .../Ext/Form/Items/Дерево/RowsPicture.bmp | Bin .../Forms/ФормаВыбораОбъектаМетаданных/Ext/Form/Module.bsl | 0 .../Forms/ФормаЭлемента.xml | 0 .../Forms/ФормаЭлемента/Ext/Form.xml | 0 .../Forms/ФормаЭлемента/Ext/Form/Module.bsl | 0 .../Catalogs/__ПользовательскиеФункции.xml | 0 .../__ПользовательскиеФункции/Ext/Help.xml | 0 .../Ext/Help/ru.html | 0 .../Ext/ManagerModule.bsl | 0 .../Ext/ObjectModule.bsl | 0 .../Forms/УсловныйОператор.xml | 0 .../Forms/УсловныйОператор/Ext/Form.xml | 0 .../Forms/УсловныйОператор/Ext/Form/Module.bsl | 0 .../Forms/ФормаВыбора.xml | 0 .../Forms/ФормаВыбора/Ext/Form.xml | 0 .../Forms/ФормаВыбора/Ext/Form/Module.bsl | 0 .../Forms/ФормаГруппы.xml | 0 .../Forms/ФормаГруппы/Ext/Form.xml | 0 .../Forms/ФормаГруппы/Ext/Form/Module.bsl | 0 .../Forms/ФормаМассива.xml | 0 .../Forms/ФормаМассива/Ext/Form.xml | 0 .../Forms/ФормаМассива/Ext/Form/Module.bsl | 0 .../Forms/ФормаСписка.xml | 0 .../Forms/ФормаСписка/Ext/Form.xml | 0 .../Forms/ФормаСписка/Ext/Form/Module.bsl | 0 .../Forms/ФормаСтруктуры.xml | 0 .../Forms/ФормаСтруктуры/Ext/Form.xml | 0 .../Forms/ФормаСтруктуры/Ext/Form/Module.bsl | 0 .../Forms/ФормаТаблицыЗначений.xml | 0 .../Forms/ФормаТаблицыЗначений/Ext/Form.xml | 0 .../Forms/ФормаТаблицыЗначений/Ext/Form/Module.bsl | 0 .../Forms/ФормаЭлемента.xml | 0 .../Forms/ФормаЭлемента/Ext/Form.xml | 0 .../Forms/ФормаЭлемента/Ext/Form/Module.bsl | 0 .../Templates/НастройкиПоУмолчанию.xml | 0 .../Templates/НастройкиПоУмолчанию/Ext/Template.txt | 0 .../Catalogs/__ТипСоответствияОбъектовИБ.xml | 0 .../Ext/ManagerModule.bsl | 0 .../Forms/ФормаСписка.xml | 0 .../Forms/ФормаСписка/Ext/Form.xml | 0 .../Forms/ФормаСписка/Ext/Form/Module.bsl | 0 .../__ПредопределенныеЗначения.xml | 0 .../Ext/ManagerModule.bsl | 0 .../Ext/ObjectModule.bsl | 0 .../Forms/ФормаГруппы.xml | 0 .../Forms/ФормаГруппы/Ext/Form.xml | 0 .../Forms/ФормаГруппы/Ext/Form/Module.bsl | 0 .../Forms/ФормаСписка.xml | 0 .../Forms/ФормаСписка/Ext/Form.xml | 0 .../Forms/ФормаСписка/Ext/Form/Module.bsl | 0 .../Forms/ФормаЭлемента.xml | 0 .../Forms/ФормаЭлемента/Ext/Form.xml | 0 .../Forms/ФормаЭлемента/Ext/Form/Module.bsl | 0 .../CommonForms/__ФормаВыбораПоля.xml | 0 .../__ФормаВыбораПоля/Ext/Form.xml | 0 .../__ФормаВыбораПоля/Ext/Form/Module.bsl | 0 .../__ФормаВыбораПоля/Ext/Help.xml | 0 .../__ФормаВыбораПоля/Ext/Help/ru.html | 0 .../__ДокументыОбработкаЗаполнения.xml | 0 .../Ext/Module.bsl | 0 .../__ДокументыОбработкаПроведения.xml | 0 .../Ext/Module.bsl | 0 .../CommonModules/__ДокументыПередЗаписью.xml | 0 .../__ДокументыПередЗаписью/Ext/Module.bsl | 0 .../CommonModules/__ДокументыПриЗаписи.xml | 0 .../__ДокументыПриЗаписи/Ext/Module.bsl | 0 .../__ДокументыПриКопировании.xml | 0 .../__ДокументыПриКопировании/Ext/Module.bsl | 0 .../CommonModules/__ЖурналРегистрации.xml | 0 .../__ЖурналРегистрации/Ext/Module.bsl | 0 .../__ЖурналРегистрацииСлужебный.xml | 0 .../Ext/Module.bsl | 0 ...зкаФайлаЧерезТабличныйДокументВызовСервера.xml | 0 .../Ext/Module.bsl | 0 ...грузкаФайлаЧерезТабличныйДокументКлиент.xml | 0 .../Ext/Module.bsl | 0 .../__ИнтеграцииПереопределяемый.xml | 0 .../Ext/Module.bsl | 0 .../CommonModules/__ИнтеграцииСервер.xml | 0 .../__ИнтеграцииСервер/Ext/Module.bsl | 0 .../CommonModules/__КоннекторHTTP.xml | 0 .../__КоннекторHTTP/Ext/Module.bsl | 0 .../__МетодыРегламентныхЗаданийСервер.xml | 0 .../Ext/Module.bsl | 0 ...фикацияКонфигурацииКлиентПереопределяемый.xml | 0 .../Ext/Module.bsl | 0 ...ацияКонфигурацииКлиентСерверПереопределяемый.xml | 0 .../Ext/Module.bsl | 0 ...одификацияКонфигурацииПереопределяемый.xml | 0 .../Ext/Module.bsl | 0 ...икацияКонфигурацииПереопределяемыйДокумент.xml | 0 .../Ext/Module.bsl | 0 ...онфигурацииПереопределяемыйПланВидовХарактеристик.xml | 0 .../Ext/Module.bsl | 0 .../__ОбновлениеИнформационнойБазыПБП.xml | 0 .../Ext/Module.bsl | 0 .../__ОбщегоНазначенияВызовСервера.xml | 0 .../Ext/Module.bsl | 0 .../__ОбщегоНазначенияКлиент.xml | 0 .../__ОбщегоНазначенияКлиент/Ext/Module.bsl | 0 .../__ОбщегоНазначенияКлиентСервер.xml | 0 .../Ext/Module.bsl | 0 .../__ОбщегоНазначенияПовтИсп.xml | 0 .../__ОбщегоНазначенияПовтИсп/Ext/Module.bsl | 0 .../__ОбщегоНазначенияПолныеПрава.xml | 0 .../Ext/Module.bsl | 0 .../__ОбщегоНазначенияСервер.xml | 0 .../__ОбщегоНазначенияСервер/Ext/Module.bsl | 0 .../__ОбщегоНазначенияСлужебный.xml | 0 .../Ext/Module.bsl | 0 .../__ОбщегоНазначенияСлужебныйКлиент.xml | 0 .../Ext/Module.bsl | 0 ..._ОбщегоНазначенияСлужебныйКлиентСервер.xml | 0 .../Ext/Module.bsl | 0 .../__ПолучениеФайловИзИнтернета.xml | 0 .../Ext/Module.bsl | 0 .../__ПолучениеФайловИзИнтернетаСлужебный.xml | 0 .../Ext/Module.bsl | 0 src/{ => cf}/CommonModules/__Пользователи.xml | 0 .../__Пользователи/Ext/Module.bsl | 0 .../__ПользователиКлиентСервер.xml | 0 .../__ПользователиКлиентСервер/Ext/Module.bsl | 0 .../CommonModules/__ПользователиСлужебный.xml | 0 .../__ПользователиСлужебный/Ext/Module.bsl | 0 .../__ПредопределенныеЗначения.xml | 0 .../__ПредопределенныеЗначения/Ext/Module.bsl | 0 ...редопределенныеЗначенияПереопределяемый.xml | 0 .../Ext/Module.bsl | 0 .../__РаботаСДиалогамиКлиент.xml | 0 .../__РаботаСДиалогамиКлиент/Ext/Module.bsl | 0 .../__РаботаСДиалогамиСервер.xml | 0 .../__РаботаСДиалогамиСервер/Ext/Module.bsl | 0 .../__РаботаСКоллекциямиКлиентСервер.xml | 0 .../Ext/Module.bsl | 0 .../CommonModules/__РаботаСФормами.xml | 0 .../__РаботаСФормами/Ext/Module.bsl | 0 .../__РегламентныеЗаданияСервер.xml | 0 .../Ext/Module.bsl | 0 .../__РегламентныеЗаданияСлужебныйСервер.xml | 0 .../Ext/Module.bsl | 0 .../__СправочникиОбработкаЗаполнения.xml | 0 .../Ext/Module.bsl | 0 .../__СправочникиПередЗаписью.xml | 0 .../__СправочникиПередЗаписью/Ext/Module.bsl | 0 .../CommonModules/__СправочникиПриЗаписи.xml | 0 .../__СправочникиПриЗаписи/Ext/Module.bsl | 0 .../__СправочникиПриКопировании.xml | 0 .../Ext/Module.bsl | 0 .../__СтандартныеПодсистемыПовтИсп.xml | 0 .../Ext/Module.bsl | 0 ..._СтандартныеПодсистемыСлужебныйПовтИсп.xml | 0 .../Ext/Module.bsl | 0 .../__СтроковыеФункцииКлиентСервер.xml | 0 .../Ext/Module.bsl | 0 ..._СтроковыеФункцииСлужебныйКлиентСервер.xml | 0 .../Ext/Module.bsl | 0 .../CommonModules/__СхемыЗапросов.xml | 0 .../__СхемыЗапросов/Ext/Module.bsl | 0 ...пСоответствияОбъектовИБПереопределяемый.xml | 0 .../Ext/Module.bsl | 0 .../__ПодсистемаУправлениеИнтеграциями.xml | 0 .../Ext/Picture.xml | 0 .../Ext/Picture/Picture.png | Bin src/{ => cf}/CommonPictures/__Реквизит.xml | 0 .../CommonPictures/__Реквизит/Ext/Picture.xml | 0 .../__Реквизит/Ext/Picture/Picture.bmp | Bin src/{ => cf}/CommonPictures/__Реквизиты.xml | 0 .../__Реквизиты/Ext/Picture.xml | 0 .../__Реквизиты/Ext/Picture/Picture.bmp | Bin src/{ => cf}/CommonTemplates/__BSLEditor.xml | 0 .../__BSLEditor/Ext/Template.bin | Bin src/{ => cf}/CommonTemplates/__JSONEditor.xml | 0 .../__JSONEditor/Ext/Template.bin | Bin src/{ => cf}/CommonTemplates/__XMLEditor.xml | 0 .../__XMLEditor/Ext/Template.bin | Bin src/{ => cf}/Configuration.xml | 0 .../ТипыОбъектовСоответствийИБ.xml | 0 src/{ => cf}/Documents/ДемоРаботаСФормами.xml | 0 .../Forms/ФормаДокумента.xml | 0 .../Forms/ФормаДокумента/Ext/Form.xml | 0 .../Forms/ФормаДокумента/Ext/Form/Module.bsl | 0 ...нтекстыВыполненияПользовательскихФункций.xml | 0 src/{ => cf}/Enums/__СозданОбновлен.xml | 0 src/{ => cf}/Enums/__СтатусыИнтеграции.xml | 0 src/{ => cf}/Enums/__ТипыJSON.xml | 0 .../Enums/__ФорматыЗапросовИнтеграции.xml | 0 .../__ДокументыОбработкаЗаполнения.xml | 0 .../__ДокументыОбработкаПроведения.xml | 0 .../__ДокументыПередЗаписью.xml | 0 .../__ДокументыПриЗаписи.xml | 0 .../__ДокументыПриКопировании.xml | 0 .../__СправочникиОбработкаЗаполнения.xml | 0 .../__СправочникиПередЗаписью.xml | 0 .../__СправочникиПриЗаписи.xml | 0 .../__СправочникиПриКопировании.xml | 0 .../__СоответствияОбъектовИБ.xml | 0 .../Ext/ManagerModule.bsl | 0 .../Forms/ФормаЗаписи.xml | 0 .../Forms/ФормаЗаписи/Ext/Form.xml | 0 .../Forms/ФормаЗаписи/Ext/Form/Module.bsl | 0 .../Forms/ФормаСписка.xml | 0 .../Forms/ФормаСписка/Ext/Form.xml | 0 .../Forms/ФормаСписка/Ext/Form/Module.bsl | 0 src/{ => cf}/Languages/English.xml | 0 src/{ => cf}/Languages/Русский.xml | 0 .../__РедактированиеДокументаДемоКаркас.xml | 0 .../Ext/Rights.xml | 0 .../__РедактированиеНастроекИнтеграции.xml | 0 .../Ext/Rights.xml | 0 ...__РедактированиеНастроекОтбораОбъектов.xml | 0 .../Ext/Rights.xml | 0 ...иеПланаВидовХарактеристикПредопределенныеЗначения.xml | 0 .../Ext/Rights.xml | 0 ..._РедактированиеПользовательскихФункций.xml | 0 .../Ext/Rights.xml | 0 ...рованиеРегистраСведенийСоответствияОбъектовИБ.xml | 0 .../Ext/Rights.xml | 0 ...дактированиеТиповСоответствияОбъектовИБ.xml | 0 .../Ext/Rights.xml | 0 .../Roles/__ЧтениеНастроекОтборовОбъектов.xml | 0 .../Ext/Rights.xml | 0 ...анаВидовХарактеристикПредопределенныеЗначения.xml | 0 .../Ext/Rights.xml | 0 ...ниеРегистраСведенийСоответствияОбъектовИБ.xml | 0 .../Ext/Rights.xml | 0 .../__ЧтениеТиповСоответствияОбъектовИБ.xml | 0 .../Ext/Rights.xml | 0 src/{ => cf}/Roles/АдминистраторСистемы.xml | 0 .../Roles/АдминистраторСистемы/Ext/Rights.xml | 0 ...рактивноеОткрытиеВнешнихОтчетовИОбработок.xml | 0 .../Ext/Rights.xml | 0 src/{ => cf}/Roles/ПолныеПрава.xml | 0 src/{ => cf}/Roles/ПолныеПрава/Ext/Rights.xml | 0 .../__ОчисткаИсторииИнтеграции.xml | 0 .../Ext/Schedule.xml | 0 .../__ЗагрузкаИзТабличногоДокумента.xml | 0 src/{ => cf}/Subsystems/__МодификацияФорм.xml | 0 .../Subsystems/__ОбщегоНазначения.xml | 0 .../Subsystems/__ПодпискиНаСобытия.xml | 0 .../Subsystems/__ПользовательскиеФункции.xml | 0 .../Subsystems/__ПредопределенныеЗначения.xml | 0 .../Subsystems/__СоответствиеОбъектовИБ.xml | 0 .../Subsystems/__УправлениеИнтеграциями.xml | 0 src/cfe/YAXUnit/CommonModules/Мокито.xml | 23 + .../CommonModules/Мокито/Ext/Module.bsl | 263 +++ .../YAXUnit/CommonModules/МокитоОбучение.xml | 23 + .../МокитоОбучение/Ext/Module.bsl | 271 +++ .../YAXUnit/CommonModules/МокитоПерехват.xml | 23 + .../МокитоПерехват/Ext/Module.bsl | 37 + .../YAXUnit/CommonModules/МокитоПроверки.xml | 23 + .../МокитоПроверки/Ext/Module.bsl | 271 +++ .../YAXUnit/CommonModules/МокитоСлужебный.xml | 23 + .../МокитоСлужебный/Ext/Module.bsl | 714 ++++++ .../CommonModules/ОМ_КоннекторHTTP.xml | 23 + .../ОМ_КоннекторHTTP/Ext/Module.bsl | 24 + .../ОМ_ОбщегоНазаначенияСервер.xml | 23 + .../ОМ_ОбщегоНазаначенияСервер/Ext/Module.bsl | 83 + .../ЮТАсинхроннаяОбработкаСлужебныйКлиент.xml | 23 + .../Ext/Module.bsl | 100 + src/cfe/YAXUnit/CommonModules/ЮТЗапросы.xml | 23 + .../CommonModules/ЮТЗапросы/Ext/Module.bsl | 238 ++ .../ЮТЗапросыСлужебныйВызовСервера.xml | 23 + .../Ext/Module.bsl | 397 ++++ .../ЮТЗапросыСлужебныйКлиентСервер.xml | 23 + .../Ext/Module.bsl | 71 + .../YAXUnit/CommonModules/ЮТИсключения.xml | 23 + .../CommonModules/ЮТИсключения/Ext/Module.bsl | 64 + .../ЮТИсполнительСлужебныйВызовСервера.xml | 23 + .../Ext/Module.bsl | 36 + .../ЮТИсполнительСлужебныйГлобальный.xml | 23 + .../Ext/Module.bsl | 27 + .../ЮТИсполнительСлужебныйКлиент.xml | 23 + .../Ext/Module.bsl | 461 ++++ .../ЮТИсполнительСлужебныйКлиентСервер.xml | 23 + .../Ext/Module.bsl | 185 ++ src/cfe/YAXUnit/CommonModules/ЮТКоллекции.xml | 23 + .../CommonModules/ЮТКоллекции/Ext/Module.bsl | 409 ++++ .../YAXUnit/CommonModules/ЮТКомпоненты.xml | 23 + .../CommonModules/ЮТКомпоненты/Ext/Module.bsl | 160 ++ .../ЮТКомпонентыСлужебныйВызовСервера.xml | 23 + .../Ext/Module.bsl | 108 + .../ЮТКомпонентыСлужебныйКлиент.xml | 23 + .../Ext/Module.bsl | 220 ++ .../CommonModules/ЮТКонструкторВариантов.xml | 23 + .../ЮТКонструкторВариантов/Ext/Module.bsl | 108 + .../ЮТКонструкторТестовыхДанныхСлужебный.xml | 23 + .../Ext/Module.bsl | 292 +++ .../CommonModules/ЮТКонтекстСлужебный.xml | 23 + .../ЮТКонтекстСлужебный/Ext/Module.bsl | 339 +++ .../ЮТКонтекстСлужебныйВызовСервера.xml | 23 + .../Ext/Module.bsl | 95 + .../ЮТКонтекстСлужебныйКлиент.xml | 23 + .../ЮТКонтекстСлужебныйКлиент/Ext/Module.bsl | 39 + .../YAXUnit/CommonModules/ЮТКонтекстТеста.xml | 23 + .../ЮТКонтекстТеста/Ext/Module.bsl | 126 ++ .../ЮТЛогИсполненияТестаСлужебный.xml | 23 + .../Ext/Module.bsl | 84 + .../YAXUnit/CommonModules/ЮТЛогирование.xml | 23 + .../ЮТЛогирование/Ext/Module.bsl | 71 + .../CommonModules/ЮТЛогированиеСлужебный.xml | 23 + .../ЮТЛогированиеСлужебный/Ext/Module.bsl | 395 ++++ .../ЮТЛогированиеСлужебныйВызовСервера.xml | 23 + .../Ext/Module.bsl | 45 + .../CommonModules/ЮТЛокальСлужебный.xml | 23 + .../ЮТЛокальСлужебный/Ext/Module.bsl | 50 + .../YAXUnit/CommonModules/ЮТМетаданные.xml | 23 + .../CommonModules/ЮТМетаданные/Ext/Module.bsl | 256 +++ .../CommonModules/ЮТМетаданныеСлужебный.xml | 23 + .../ЮТМетаданныеСлужебный/Ext/Module.bsl | 31 + .../ЮТМетаданныеСлужебныйВызовСервера.xml | 23 + .../Ext/Module.bsl | 379 ++++ .../ЮТМетаданныеСлужебныйПовтИсп.xml | 23 + .../Ext/Module.bsl | 70 + .../CommonModules/ЮТМетодыСлужебный.xml | 23 + .../ЮТМетодыСлужебный/Ext/Module.bsl | 185 ++ .../CommonModules/ЮТНастройкиВыполнения.xml | 23 + .../ЮТНастройкиВыполнения/Ext/Module.bsl | 121 + src/cfe/YAXUnit/CommonModules/ЮТОбщий.xml | 23 + .../CommonModules/ЮТОбщий/Ext/Module.bsl | 890 ++++++++ .../ЮТОбщийСлужебныйВызовСервера.xml | 23 + .../Ext/Module.bsl | 147 ++ .../CommonModules/ЮТОтчетAllureСлужебный.xml | 23 + .../ЮТОтчетAllureСлужебный/Ext/Module.bsl | 266 +++ .../CommonModules/ЮТОтчетJSONСлужебный.xml | 23 + .../ЮТОтчетJSONСлужебный/Ext/Module.bsl | 59 + .../CommonModules/ЮТОтчетJUnitСлужебный.xml | 23 + .../ЮТОтчетJUnitСлужебный/Ext/Module.bsl | 344 +++ .../CommonModules/ЮТОтчетСлужебный.xml | 23 + .../ЮТОтчетСлужебный/Ext/Module.bsl | 169 ++ .../ЮТПараметрыЗапускаСлужебный.xml | 23 + .../Ext/Module.bsl | 175 ++ .../YAXUnit/CommonModules/ЮТПодражатель.xml | 23 + .../ЮТПодражатель/Ext/Module.bsl | 65 + .../CommonModules/ЮТПодражатель_Банки.xml | 23 + .../ЮТПодражатель_Банки/Ext/Module.bsl | 85 + .../CommonModules/ЮТПодражатель_Компании.xml | 23 + .../ЮТПодражатель_Компании/Ext/Module.bsl | 150 ++ .../CommonModules/ЮТПодражатель_Люди.xml | 23 + .../ЮТПодражатель_Люди/Ext/Module.bsl | 204 ++ .../CommonModules/ЮТПодражательСлужебный.xml | 23 + .../ЮТПодражательСлужебный/Ext/Module.bsl | 87 + .../ЮТПодражательСлужебныйВызовСервера.xml | 23 + .../Ext/Module.bsl | 38 + .../ЮТПодражательСлужебныйПовтИсп.xml | 23 + .../Ext/Module.bsl | 48 + src/cfe/YAXUnit/CommonModules/ЮТПредикаты.xml | 23 + .../CommonModules/ЮТПредикаты/Ext/Module.bsl | 440 ++++ .../ЮТПредикатыСлужебныйКлиентСервер.xml | 23 + .../Ext/Module.bsl | 235 ++ .../ЮТПреобразованияСлужебный.xml | 23 + .../ЮТПреобразованияСлужебный/Ext/Module.bsl | 230 ++ .../CommonModules/ЮТПроверкиСлужебный.xml | 23 + .../ЮТПроверкиСлужебный/Ext/Module.bsl | 69 + .../CommonModules/ЮТРасширенияСлужебный.xml | 23 + .../ЮТРасширенияСлужебный/Ext/Module.bsl | 64 + .../CommonModules/ЮТРегистрацияОшибок.xml | 23 + .../ЮТРегистрацияОшибок/Ext/Module.bsl | 36 + .../ЮТРегистрацияОшибокСлужебный.xml | 23 + .../Ext/Module.bsl | 698 ++++++ .../ЮТСлужебныйПовторногоИспользования.xml | 23 + .../Ext/Module.bsl | 94 + .../CommonModules/ЮТСобытияСлужебный.xml | 23 + .../ЮТСобытияСлужебный/Ext/Module.bsl | 364 +++ .../CommonModules/ЮТСообщенияСлужебный.xml | 23 + .../ЮТСообщенияСлужебный/Ext/Module.bsl | 127 ++ .../ЮТСравнениеСлужебныйВызовСервера.xml | 23 + .../Ext/Module.bsl | 119 + .../ЮТСравнениеСлужебныйКлиентСервер.xml | 23 + .../Ext/Module.bsl | 657 ++++++ src/cfe/YAXUnit/CommonModules/ЮТСтроки.xml | 23 + .../CommonModules/ЮТСтроки/Ext/Module.bsl | 188 ++ .../CommonModules/ЮТТестовыеДанные.xml | 23 + .../ЮТТестовыеДанные/Ext/Module.bsl | 881 ++++++++ .../ЮТТестовыеДанныеСлужебный.xml | 23 + .../ЮТТестовыеДанныеСлужебный/Ext/Module.bsl | 254 +++ .../ЮТТестовыеДанныеСлужебныйВызовСервера.xml | 23 + .../Ext/Module.bsl | 420 ++++ ...ТТестовыеДанныеСлужебныйТаблицыЗначений.xml | 23 + .../Ext/Module.bsl | 562 +++++ src/cfe/YAXUnit/CommonModules/ЮТТесты.xml | 23 + .../CommonModules/ЮТТесты/Ext/Module.bsl | 353 +++ .../CommonModules/ЮТТестыСлужебный.xml | 23 + .../ЮТТестыСлужебный/Ext/Module.bsl | 287 +++ .../CommonModules/ЮТТипыДанныхСлужебный.xml | 23 + .../ЮТТипыДанныхСлужебный/Ext/Module.bsl | 231 ++ .../YAXUnit/CommonModules/ЮТУтверждения.xml | 23 + .../ЮТУтверждения/Ext/Module.bsl | 1945 +++++++++++++++++ .../YAXUnit/CommonModules/ЮТУтвержденияИБ.xml | 23 + .../ЮТУтвержденияИБ/Ext/Module.bsl | 300 +++ src/cfe/YAXUnit/CommonModules/ЮТФабрика.xml | 23 + .../CommonModules/ЮТФабрика/Ext/Module.bsl | 283 +++ .../CommonModules/ЮТФабрикаСлужебный.xml | 23 + .../ЮТФабрикаСлужебный/Ext/Module.bsl | 684 ++++++ src/cfe/YAXUnit/CommonModules/ЮТФайлы.xml | 23 + .../CommonModules/ЮТФайлы/Ext/Module.bsl | 201 ++ .../CommonModules/ЮТФильтрацияСлужебный.xml | 23 + .../ЮТФильтрацияСлужебный/Ext/Module.bsl | 294 +++ .../CommonModules/ЮТЧитательСлужебный.xml | 23 + .../ЮТЧитательСлужебный/Ext/Module.bsl | 235 ++ .../ЮТЧитательСлужебныйВызовСервера.xml | 23 + .../Ext/Module.bsl | 34 + src/cfe/YAXUnit/CommonModules/ЮТест.xml | 23 + .../CommonModules/ЮТест/Ext/Module.bsl | 206 ++ .../YAXUnit/CommonPictures/ЮТЗапустить.xml | 17 + .../ЮТЗапустить/Ext/Picture.xml | 7 + .../ЮТЗапустить/Ext/Picture/Picture.svg | 4 + .../YAXUnit/CommonPictures/ЮТНеизвестный.xml | 17 + .../ЮТНеизвестный/Ext/Picture.xml | 7 + .../ЮТНеизвестный/Ext/Picture/Picture.svg | 4 + src/cfe/YAXUnit/CommonPictures/ЮТОшибка.xml | 17 + .../CommonPictures/ЮТОшибка/Ext/Picture.xml | 7 + .../ЮТОшибка/Ext/Picture/Picture.svg | 6 + .../CommonPictures/ЮТПерезапуститьУпавшие.xml | 17 + .../ЮТПерезапуститьУпавшие/Ext/Picture.xml | 7 + .../Ext/Picture/Picture.svg | 16 + .../YAXUnit/CommonPictures/ЮТПодсистема.xml | 17 + .../ЮТПодсистема/Ext/Picture.xml | 7 + .../ЮТПодсистема/Ext/Picture/Picture.png | Bin 0 -> 706 bytes src/cfe/YAXUnit/CommonPictures/ЮТПропущен.xml | 17 + .../CommonPictures/ЮТПропущен/Ext/Picture.xml | 7 + .../ЮТПропущен/Ext/Picture/Picture.svg | 5 + src/cfe/YAXUnit/CommonPictures/ЮТСравнить.xml | 17 + .../CommonPictures/ЮТСравнить/Ext/Picture.xml | 7 + .../ЮТСравнить/Ext/Picture/Picture.svg | 7 + src/cfe/YAXUnit/CommonPictures/ЮТУпал.xml | 17 + .../CommonPictures/ЮТУпал/Ext/Picture.xml | 7 + .../ЮТУпал/Ext/Picture/Picture.svg | 6 + src/cfe/YAXUnit/CommonPictures/ЮТУспешно.xml | 17 + .../CommonPictures/ЮТУспешно/Ext/Picture.xml | 7 + .../ЮТУспешно/Ext/Picture/Picture.svg | 4 + .../CommonPictures/ЮТЭлементыТестов.xml | 17 + .../ЮТЭлементыТестов/Ext/Picture.xml | 7 + .../ЮТЭлементыТестов/Ext/Picture/Picture.svg | 30 + .../CommonTemplates/ЮТRegEx1CAddin.xml | 16 + .../ЮТRegEx1CAddin/Ext/Template.bin | Bin 0 -> 528812 bytes .../CommonTemplates/ЮТYaxUnitAddIn.xml | 16 + .../ЮТYaxUnitAddIn/Ext/Template.bin | Bin 0 -> 106819 bytes ...оварьПодражателя_Компании_Наименования_ru.xml | 16 + .../Ext/Template.txt | 33 + ...ьПодражателя_Компании_ПрефиксыНаименований_ru.xml | 16 + .../Ext/Template.txt | 12 + ..._СловарьПодражателя_Люди_ЖенскиеИмена_ru.xml | 16 + .../Ext/Template.txt | 80 + ...ловарьПодражателя_Люди_ЖенскиеОтчества_ru.xml | 16 + .../Ext/Template.txt | 79 + ...ловарьПодражателя_Люди_ЖенскиеФамилии_ru.xml | 16 + .../Ext/Template.txt | 250 +++ ..._СловарьПодражателя_Люди_МужскиеИмена_ru.xml | 16 + .../Ext/Template.txt | 321 +++ ...ловарьПодражателя_Люди_МужскиеОтчества_ru.xml | 16 + .../Ext/Template.txt | 132 ++ ...ловарьПодражателя_Люди_МужскиеФамилии_ru.xml | 16 + .../Ext/Template.txt | 250 +++ .../CommonTemplates/ЮТИнформацияОбОшибке.xml | 16 + .../ЮТИнформацияОбОшибке/Ext/Template.txt | 167 ++ .../CommonTemplates/ЮТОписаниеМетаданных.xml | 16 + .../ЮТОписаниеМетаданных/Ext/Template.txt | 34 + src/cfe/YAXUnit/Configuration.xml | 172 ++ .../DataProcessors/ЮТHTTPServiceRequest.xml | 32 + .../ЮТHTTPServiceRequest/Ext/ObjectModule.bsl | 252 +++ .../DataProcessors/ЮТHTTPСервисЗапрос.xml | 32 + .../ЮТHTTPСервисЗапрос/Ext/ObjectModule.bsl | 252 +++ .../YAXUnit/DataProcessors/ЮТRecordSet.xml | 217 ++ .../ЮТRecordSet/Ext/ObjectModule.bsl | 187 ++ .../ЮТКонструкторОбъектаXDTO.xml | 32 + .../Ext/ObjectModule.bsl | 375 ++++ .../ЮТКонструкторТестовыхДанных.xml | 34 + .../Ext/ObjectModule.bsl | 261 +++ .../Forms/КлиентскийКонструктор.xml | 22 + .../Forms/КлиентскийКонструктор/Ext/Form.xml | 6 + .../Forms/КлиентскийКонструктор/Ext/Form/Module.bsl | 277 +++ .../YAXUnit/DataProcessors/ЮТЮнитТесты.xml | 83 + .../Commands/ЗапускТестов/Ext/CommandModule.bsl | 35 + .../Ext/CommandModule.bsl | 33 + .../ЮТЮнитТесты/Forms/Основная.xml | 22 + .../ЮТЮнитТесты/Forms/Основная/Ext/Form.xml | 929 ++++++++ .../Forms/Основная/Ext/Form/Module.bsl | 986 +++++++++ .../ЮТЮнитТесты/Forms/СозданиеНастройки.xml | 22 + .../Forms/СозданиеНастройки/Ext/Form.xml | 577 +++++ .../Forms/СозданиеНастройки/Ext/Form/Module.bsl | 587 +++++ .../ЮТЮнитТесты/Forms/Сравнение.xml | 22 + .../ЮТЮнитТесты/Forms/Сравнение/Ext/Form.xml | 38 + .../Forms/Сравнение/Ext/Form/Module.bsl | 34 + .../ЮТЮнитТесты/Templates/Сравнение.xml | 16 + .../Templates/Сравнение/Ext/Template.txt | 61 + .../ЮТЮнитТесты/Templates/СравнениеOld.xml | 16 + .../Templates/СравнениеOld/Ext/Template.txt | 936 ++++++++ .../YAXUnit/Ext/ManagedApplicationModule.bsl | 50 + .../YAXUnit/Ext/OrdinaryApplicationModule.bsl | 43 + src/cfe/YAXUnit/Languages/Русский.xml | 12 + src/cfe/YAXUnit/Subsystems/ЮТДвижок.xml | 34 + .../ЮТДвижок/Subsystems/ЮТИсполнитель.xml | 37 + .../ЮТДвижок/Subsystems/ЮТКонтекст.xml | 32 + .../ЮТДвижок/Subsystems/ЮТМокирование.xml | 34 + .../ЮТДвижок/Subsystems/ЮТСервис.xml | 59 + .../ЮТДвижок/Subsystems/ЮТТестовыеДанные.xml | 39 + .../ЮТТестовыеДанные/Subsystems/ЮТПодражатель.xml | 38 + .../ЮТДвижок/Subsystems/ЮТУтверждения.xml | 36 + .../Subsystems/ЮТДинамическиПодключаемые.xml | 30 + .../Subsystems/ЮТОбработчикиСобытий.xml | 33 + .../Subsystems/ЮТФормированиеОтчета.xml | 31 + src/cfe/YAXUnit/Subsystems/ЮТПубличный.xml | 62 + tools/VBParams.json | 6 +- tools/yaxunit.json | 26 + 546 files changed, 31080 insertions(+), 32 deletions(-) create mode 100644 docs/РуководствоПоНаписаниюТестовYAxUnit.md create mode 100644 features/Проверка пометки на удаление.feature create mode 100644 features/Создание элемента справочника.feature rename src/{ => cf}/Catalogs/__ИнтегрируемыеСистемы.xml (100%) rename src/{ => cf}/Catalogs/__ИнтегрируемыеСистемы/Ext/ManagerModule.bsl (100%) rename src/{ => cf}/Catalogs/__ИнтегрируемыеСистемы/Forms/ФормаСписка.xml (100%) rename src/{ => cf}/Catalogs/__ИнтегрируемыеСистемы/Forms/ФормаСписка/Ext/Form.xml (100%) rename src/{ => cf}/Catalogs/__ИнтегрируемыеСистемы/Forms/ФормаСписка/Ext/Form/Module.bsl (100%) rename src/{ => cf}/Catalogs/__ИнтегрируемыеСистемы/Forms/ФормаЭлемента.xml (100%) rename src/{ => cf}/Catalogs/__ИнтегрируемыеСистемы/Forms/ФормаЭлемента/Ext/Form.xml (100%) rename src/{ => cf}/Catalogs/__ИсторияИнтеграции.xml (100%) rename src/{ => cf}/Catalogs/__ИсторияИнтеграции/Ext/ManagerModule.bsl (100%) rename src/{ => cf}/Catalogs/__ИсторияИнтеграции/Ext/ObjectModule.bsl (100%) rename src/{ => cf}/Catalogs/__ИсторияИнтеграции/Forms/ФормаСписка.xml (100%) rename src/{ => cf}/Catalogs/__ИсторияИнтеграции/Forms/ФормаСписка/Ext/Form.xml (100%) rename src/{ => cf}/Catalogs/__ИсторияИнтеграции/Forms/ФормаСписка/Ext/Form/Module.bsl (100%) rename src/{ => cf}/Catalogs/__ИсторияИнтеграции/Forms/ФормаЭлемента.xml (100%) rename src/{ => cf}/Catalogs/__ИсторияИнтеграции/Forms/ФормаЭлемента/Ext/Form.xml (100%) rename src/{ => cf}/Catalogs/__ИсторияИнтеграции/Forms/ФормаЭлемента/Ext/Form/Module.bsl (100%) rename src/{ => cf}/Catalogs/__МетодыИнтеграции.xml (100%) rename src/{ => cf}/Catalogs/__МетодыИнтеграции/Ext/ManagerModule.bsl (100%) rename src/{ => cf}/Catalogs/__МетодыИнтеграции/Forms/ФормаСписка.xml (100%) rename src/{ => cf}/Catalogs/__МетодыИнтеграции/Forms/ФормаСписка/Ext/Form.xml (100%) rename src/{ => cf}/Catalogs/__МетодыИнтеграции/Forms/ФормаСписка/Ext/Form/Module.bsl (100%) rename src/{ => cf}/Catalogs/__МетодыИнтеграции/Forms/ФормаЭлемента.xml (100%) rename src/{ => cf}/Catalogs/__МетодыИнтеграции/Forms/ФормаЭлемента/Ext/Form.xml (100%) rename src/{ => cf}/Catalogs/__НастройкиИнтеграции.xml (100%) rename src/{ => cf}/Catalogs/__НастройкиИнтеграции/Ext/ManagerModule.bsl (100%) rename src/{ => cf}/Catalogs/__НастройкиИнтеграции/Forms/ФормаСписка.xml (100%) rename src/{ => cf}/Catalogs/__НастройкиИнтеграции/Forms/ФормаСписка/Ext/Form.xml (100%) rename src/{ => cf}/Catalogs/__НастройкиИнтеграции/Forms/ФормаСписка/Ext/Form/Module.bsl (100%) rename src/{ => cf}/Catalogs/__НастройкиИнтеграции/Forms/ФормаЭлемента.xml (100%) rename src/{ => cf}/Catalogs/__НастройкиИнтеграции/Forms/ФормаЭлемента/Ext/Form.xml (100%) rename src/{ => cf}/Catalogs/__НастройкиИнтеграции/Forms/ФормаЭлемента/Ext/Form/Module.bsl (100%) rename src/{ => cf}/Catalogs/__НастройкиОтбораОбъектов.xml (100%) rename src/{ => cf}/Catalogs/__НастройкиОтбораОбъектов/Ext/ManagerModule.bsl (100%) rename src/{ => cf}/Catalogs/__НастройкиОтбораОбъектов/Forms/ФормаВыбораОбъектаМетаданных.xml (100%) rename src/{ => cf}/Catalogs/__НастройкиОтбораОбъектов/Forms/ФормаВыбораОбъектаМетаданных/Ext/Form.xml (100%) rename src/{ => cf}/Catalogs/__НастройкиОтбораОбъектов/Forms/ФормаВыбораОбъектаМетаданных/Ext/Form/Items/Дерево/RowsPicture.bmp (100%) rename src/{ => cf}/Catalogs/__НастройкиОтбораОбъектов/Forms/ФормаВыбораОбъектаМетаданных/Ext/Form/Module.bsl (100%) rename src/{ => cf}/Catalogs/__НастройкиОтбораОбъектов/Forms/ФормаЭлемента.xml (100%) rename src/{ => cf}/Catalogs/__НастройкиОтбораОбъектов/Forms/ФормаЭлемента/Ext/Form.xml (100%) rename src/{ => cf}/Catalogs/__НастройкиОтбораОбъектов/Forms/ФормаЭлемента/Ext/Form/Module.bsl (100%) rename src/{ => cf}/Catalogs/__ПользовательскиеФункции.xml (100%) rename src/{ => cf}/Catalogs/__ПользовательскиеФункции/Ext/Help.xml (100%) rename src/{ => cf}/Catalogs/__ПользовательскиеФункции/Ext/Help/ru.html (100%) rename src/{ => cf}/Catalogs/__ПользовательскиеФункции/Ext/ManagerModule.bsl (100%) rename src/{ => cf}/Catalogs/__ПользовательскиеФункции/Ext/ObjectModule.bsl (100%) rename src/{ => cf}/Catalogs/__ПользовательскиеФункции/Forms/УсловныйОператор.xml (100%) rename src/{ => cf}/Catalogs/__ПользовательскиеФункции/Forms/УсловныйОператор/Ext/Form.xml (100%) rename src/{ => cf}/Catalogs/__ПользовательскиеФункции/Forms/УсловныйОператор/Ext/Form/Module.bsl (100%) rename src/{ => cf}/Catalogs/__ПользовательскиеФункции/Forms/ФормаВыбора.xml (100%) rename src/{ => cf}/Catalogs/__ПользовательскиеФункции/Forms/ФормаВыбора/Ext/Form.xml (100%) rename src/{ => cf}/Catalogs/__ПользовательскиеФункции/Forms/ФормаВыбора/Ext/Form/Module.bsl (100%) rename src/{ => cf}/Catalogs/__ПользовательскиеФункции/Forms/ФормаГруппы.xml (100%) rename src/{ => cf}/Catalogs/__ПользовательскиеФункции/Forms/ФормаГруппы/Ext/Form.xml (100%) rename src/{ => cf}/Catalogs/__ПользовательскиеФункции/Forms/ФормаГруппы/Ext/Form/Module.bsl (100%) rename src/{ => cf}/Catalogs/__ПользовательскиеФункции/Forms/ФормаМассива.xml (100%) rename src/{ => cf}/Catalogs/__ПользовательскиеФункции/Forms/ФормаМассива/Ext/Form.xml (100%) rename src/{ => cf}/Catalogs/__ПользовательскиеФункции/Forms/ФормаМассива/Ext/Form/Module.bsl (100%) rename src/{ => cf}/Catalogs/__ПользовательскиеФункции/Forms/ФормаСписка.xml (100%) rename src/{ => cf}/Catalogs/__ПользовательскиеФункции/Forms/ФормаСписка/Ext/Form.xml (100%) rename src/{ => cf}/Catalogs/__ПользовательскиеФункции/Forms/ФормаСписка/Ext/Form/Module.bsl (100%) rename src/{ => cf}/Catalogs/__ПользовательскиеФункции/Forms/ФормаСтруктуры.xml (100%) rename src/{ => cf}/Catalogs/__ПользовательскиеФункции/Forms/ФормаСтруктуры/Ext/Form.xml (100%) rename src/{ => cf}/Catalogs/__ПользовательскиеФункции/Forms/ФормаСтруктуры/Ext/Form/Module.bsl (100%) rename src/{ => cf}/Catalogs/__ПользовательскиеФункции/Forms/ФормаТаблицыЗначений.xml (100%) rename src/{ => cf}/Catalogs/__ПользовательскиеФункции/Forms/ФормаТаблицыЗначений/Ext/Form.xml (100%) rename src/{ => cf}/Catalogs/__ПользовательскиеФункции/Forms/ФормаТаблицыЗначений/Ext/Form/Module.bsl (100%) rename src/{ => cf}/Catalogs/__ПользовательскиеФункции/Forms/ФормаЭлемента.xml (100%) rename src/{ => cf}/Catalogs/__ПользовательскиеФункции/Forms/ФормаЭлемента/Ext/Form.xml (100%) rename src/{ => cf}/Catalogs/__ПользовательскиеФункции/Forms/ФормаЭлемента/Ext/Form/Module.bsl (100%) rename src/{ => cf}/Catalogs/__ПользовательскиеФункции/Templates/НастройкиПоУмолчанию.xml (100%) rename src/{ => cf}/Catalogs/__ПользовательскиеФункции/Templates/НастройкиПоУмолчанию/Ext/Template.txt (100%) rename src/{ => cf}/Catalogs/__ТипСоответствияОбъектовИБ.xml (100%) rename src/{ => cf}/Catalogs/__ТипСоответствияОбъектовИБ/Ext/ManagerModule.bsl (100%) rename src/{ => cf}/Catalogs/__ТипСоответствияОбъектовИБ/Forms/ФормаСписка.xml (100%) rename src/{ => cf}/Catalogs/__ТипСоответствияОбъектовИБ/Forms/ФормаСписка/Ext/Form.xml (100%) rename src/{ => cf}/Catalogs/__ТипСоответствияОбъектовИБ/Forms/ФормаСписка/Ext/Form/Module.bsl (100%) rename src/{ => cf}/ChartsOfCharacteristicTypes/__ПредопределенныеЗначения.xml (100%) rename src/{ => cf}/ChartsOfCharacteristicTypes/__ПредопределенныеЗначения/Ext/ManagerModule.bsl (100%) rename src/{ => cf}/ChartsOfCharacteristicTypes/__ПредопределенныеЗначения/Ext/ObjectModule.bsl (100%) rename src/{ => cf}/ChartsOfCharacteristicTypes/__ПредопределенныеЗначения/Forms/ФормаГруппы.xml (100%) rename src/{ => cf}/ChartsOfCharacteristicTypes/__ПредопределенныеЗначения/Forms/ФормаГруппы/Ext/Form.xml (100%) rename src/{ => cf}/ChartsOfCharacteristicTypes/__ПредопределенныеЗначения/Forms/ФормаГруппы/Ext/Form/Module.bsl (100%) rename src/{ => cf}/ChartsOfCharacteristicTypes/__ПредопределенныеЗначения/Forms/ФормаСписка.xml (100%) rename src/{ => cf}/ChartsOfCharacteristicTypes/__ПредопределенныеЗначения/Forms/ФормаСписка/Ext/Form.xml (100%) rename src/{ => cf}/ChartsOfCharacteristicTypes/__ПредопределенныеЗначения/Forms/ФормаСписка/Ext/Form/Module.bsl (100%) rename src/{ => cf}/ChartsOfCharacteristicTypes/__ПредопределенныеЗначения/Forms/ФормаЭлемента.xml (100%) rename src/{ => cf}/ChartsOfCharacteristicTypes/__ПредопределенныеЗначения/Forms/ФормаЭлемента/Ext/Form.xml (100%) rename src/{ => cf}/ChartsOfCharacteristicTypes/__ПредопределенныеЗначения/Forms/ФормаЭлемента/Ext/Form/Module.bsl (100%) rename src/{ => cf}/CommonForms/__ФормаВыбораПоля.xml (100%) rename src/{ => cf}/CommonForms/__ФормаВыбораПоля/Ext/Form.xml (100%) rename src/{ => cf}/CommonForms/__ФормаВыбораПоля/Ext/Form/Module.bsl (100%) rename src/{ => cf}/CommonForms/__ФормаВыбораПоля/Ext/Help.xml (100%) rename src/{ => cf}/CommonForms/__ФормаВыбораПоля/Ext/Help/ru.html (100%) rename src/{ => cf}/CommonModules/__ДокументыОбработкаЗаполнения.xml (100%) rename src/{ => cf}/CommonModules/__ДокументыОбработкаЗаполнения/Ext/Module.bsl (100%) rename src/{ => cf}/CommonModules/__ДокументыОбработкаПроведения.xml (100%) rename src/{ => cf}/CommonModules/__ДокументыОбработкаПроведения/Ext/Module.bsl (100%) rename src/{ => cf}/CommonModules/__ДокументыПередЗаписью.xml (100%) rename src/{ => cf}/CommonModules/__ДокументыПередЗаписью/Ext/Module.bsl (100%) rename src/{ => cf}/CommonModules/__ДокументыПриЗаписи.xml (100%) rename src/{ => cf}/CommonModules/__ДокументыПриЗаписи/Ext/Module.bsl (100%) rename src/{ => cf}/CommonModules/__ДокументыПриКопировании.xml (100%) rename src/{ => cf}/CommonModules/__ДокументыПриКопировании/Ext/Module.bsl (100%) rename src/{ => cf}/CommonModules/__ЖурналРегистрации.xml (100%) rename src/{ => cf}/CommonModules/__ЖурналРегистрации/Ext/Module.bsl (100%) rename src/{ => cf}/CommonModules/__ЖурналРегистрацииСлужебный.xml (100%) rename src/{ => cf}/CommonModules/__ЖурналРегистрацииСлужебный/Ext/Module.bsl (100%) rename src/{ => cf}/CommonModules/__ЗагрузкаФайлаЧерезТабличныйДокументВызовСервера.xml (100%) rename src/{ => cf}/CommonModules/__ЗагрузкаФайлаЧерезТабличныйДокументВызовСервера/Ext/Module.bsl (100%) rename src/{ => cf}/CommonModules/__ЗагрузкаФайлаЧерезТабличныйДокументКлиент.xml (100%) rename src/{ => cf}/CommonModules/__ЗагрузкаФайлаЧерезТабличныйДокументКлиент/Ext/Module.bsl (100%) rename src/{ => cf}/CommonModules/__ИнтеграцииПереопределяемый.xml (100%) rename src/{ => cf}/CommonModules/__ИнтеграцииПереопределяемый/Ext/Module.bsl (100%) rename src/{ => cf}/CommonModules/__ИнтеграцииСервер.xml (100%) rename src/{ => cf}/CommonModules/__ИнтеграцииСервер/Ext/Module.bsl (100%) rename src/{ => cf}/CommonModules/__КоннекторHTTP.xml (100%) rename src/{ => cf}/CommonModules/__КоннекторHTTP/Ext/Module.bsl (100%) rename src/{ => cf}/CommonModules/__МетодыРегламентныхЗаданийСервер.xml (100%) rename src/{ => cf}/CommonModules/__МетодыРегламентныхЗаданийСервер/Ext/Module.bsl (100%) rename src/{ => cf}/CommonModules/__МодификацияКонфигурацииКлиентПереопределяемый.xml (100%) rename src/{ => cf}/CommonModules/__МодификацияКонфигурацииКлиентПереопределяемый/Ext/Module.bsl (100%) rename src/{ => cf}/CommonModules/__МодификацияКонфигурацииКлиентСерверПереопределяемый.xml (100%) rename src/{ => cf}/CommonModules/__МодификацияКонфигурацииКлиентСерверПереопределяемый/Ext/Module.bsl (100%) rename src/{ => cf}/CommonModules/__МодификацияКонфигурацииПереопределяемый.xml (100%) rename src/{ => cf}/CommonModules/__МодификацияКонфигурацииПереопределяемый/Ext/Module.bsl (100%) rename src/{ => cf}/CommonModules/__МодификацияКонфигурацииПереопределяемыйДокумент.xml (100%) rename src/{ => cf}/CommonModules/__МодификацияКонфигурацииПереопределяемыйДокумент/Ext/Module.bsl (100%) rename src/{ => cf}/CommonModules/__МодификацияКонфигурацииПереопределяемыйПланВидовХарактеристик.xml (100%) rename src/{ => cf}/CommonModules/__МодификацияКонфигурацииПереопределяемыйПланВидовХарактеристик/Ext/Module.bsl (100%) rename src/{ => cf}/CommonModules/__ОбновлениеИнформационнойБазыПБП.xml (100%) rename src/{ => cf}/CommonModules/__ОбновлениеИнформационнойБазыПБП/Ext/Module.bsl (100%) rename src/{ => cf}/CommonModules/__ОбщегоНазначенияВызовСервера.xml (100%) rename src/{ => cf}/CommonModules/__ОбщегоНазначенияВызовСервера/Ext/Module.bsl (100%) rename src/{ => cf}/CommonModules/__ОбщегоНазначенияКлиент.xml (100%) rename src/{ => cf}/CommonModules/__ОбщегоНазначенияКлиент/Ext/Module.bsl (100%) rename src/{ => cf}/CommonModules/__ОбщегоНазначенияКлиентСервер.xml (100%) rename src/{ => cf}/CommonModules/__ОбщегоНазначенияКлиентСервер/Ext/Module.bsl (100%) rename src/{ => cf}/CommonModules/__ОбщегоНазначенияПовтИсп.xml (100%) rename src/{ => cf}/CommonModules/__ОбщегоНазначенияПовтИсп/Ext/Module.bsl (100%) rename src/{ => cf}/CommonModules/__ОбщегоНазначенияПолныеПрава.xml (100%) rename src/{ => cf}/CommonModules/__ОбщегоНазначенияПолныеПрава/Ext/Module.bsl (100%) rename src/{ => cf}/CommonModules/__ОбщегоНазначенияСервер.xml (100%) rename src/{ => cf}/CommonModules/__ОбщегоНазначенияСервер/Ext/Module.bsl (100%) rename src/{ => cf}/CommonModules/__ОбщегоНазначенияСлужебный.xml (100%) rename src/{ => cf}/CommonModules/__ОбщегоНазначенияСлужебный/Ext/Module.bsl (100%) rename src/{ => cf}/CommonModules/__ОбщегоНазначенияСлужебныйКлиент.xml (100%) rename src/{ => cf}/CommonModules/__ОбщегоНазначенияСлужебныйКлиент/Ext/Module.bsl (100%) rename src/{ => cf}/CommonModules/__ОбщегоНазначенияСлужебныйКлиентСервер.xml (100%) rename src/{ => cf}/CommonModules/__ОбщегоНазначенияСлужебныйКлиентСервер/Ext/Module.bsl (100%) rename src/{ => cf}/CommonModules/__ПолучениеФайловИзИнтернета.xml (100%) rename src/{ => cf}/CommonModules/__ПолучениеФайловИзИнтернета/Ext/Module.bsl (100%) rename src/{ => cf}/CommonModules/__ПолучениеФайловИзИнтернетаСлужебный.xml (100%) rename src/{ => cf}/CommonModules/__ПолучениеФайловИзИнтернетаСлужебный/Ext/Module.bsl (100%) rename src/{ => cf}/CommonModules/__Пользователи.xml (100%) rename src/{ => cf}/CommonModules/__Пользователи/Ext/Module.bsl (100%) rename src/{ => cf}/CommonModules/__ПользователиКлиентСервер.xml (100%) rename src/{ => cf}/CommonModules/__ПользователиКлиентСервер/Ext/Module.bsl (100%) rename src/{ => cf}/CommonModules/__ПользователиСлужебный.xml (100%) rename src/{ => cf}/CommonModules/__ПользователиСлужебный/Ext/Module.bsl (100%) rename src/{ => cf}/CommonModules/__ПредопределенныеЗначения.xml (100%) rename src/{ => cf}/CommonModules/__ПредопределенныеЗначения/Ext/Module.bsl (100%) rename src/{ => cf}/CommonModules/__ПредопределенныеЗначенияПереопределяемый.xml (100%) rename src/{ => cf}/CommonModules/__ПредопределенныеЗначенияПереопределяемый/Ext/Module.bsl (100%) rename src/{ => cf}/CommonModules/__РаботаСДиалогамиКлиент.xml (100%) rename src/{ => cf}/CommonModules/__РаботаСДиалогамиКлиент/Ext/Module.bsl (100%) rename src/{ => cf}/CommonModules/__РаботаСДиалогамиСервер.xml (100%) rename src/{ => cf}/CommonModules/__РаботаСДиалогамиСервер/Ext/Module.bsl (100%) rename src/{ => cf}/CommonModules/__РаботаСКоллекциямиКлиентСервер.xml (100%) rename src/{ => cf}/CommonModules/__РаботаСКоллекциямиКлиентСервер/Ext/Module.bsl (100%) rename src/{ => cf}/CommonModules/__РаботаСФормами.xml (100%) rename src/{ => cf}/CommonModules/__РаботаСФормами/Ext/Module.bsl (100%) rename src/{ => cf}/CommonModules/__РегламентныеЗаданияСервер.xml (100%) rename src/{ => cf}/CommonModules/__РегламентныеЗаданияСервер/Ext/Module.bsl (100%) rename src/{ => cf}/CommonModules/__РегламентныеЗаданияСлужебныйСервер.xml (100%) rename src/{ => cf}/CommonModules/__РегламентныеЗаданияСлужебныйСервер/Ext/Module.bsl (100%) rename src/{ => cf}/CommonModules/__СправочникиОбработкаЗаполнения.xml (100%) rename src/{ => cf}/CommonModules/__СправочникиОбработкаЗаполнения/Ext/Module.bsl (100%) rename src/{ => cf}/CommonModules/__СправочникиПередЗаписью.xml (100%) rename src/{ => cf}/CommonModules/__СправочникиПередЗаписью/Ext/Module.bsl (100%) rename src/{ => cf}/CommonModules/__СправочникиПриЗаписи.xml (100%) rename src/{ => cf}/CommonModules/__СправочникиПриЗаписи/Ext/Module.bsl (100%) rename src/{ => cf}/CommonModules/__СправочникиПриКопировании.xml (100%) rename src/{ => cf}/CommonModules/__СправочникиПриКопировании/Ext/Module.bsl (100%) rename src/{ => cf}/CommonModules/__СтандартныеПодсистемыПовтИсп.xml (100%) rename src/{ => cf}/CommonModules/__СтандартныеПодсистемыПовтИсп/Ext/Module.bsl (100%) rename src/{ => cf}/CommonModules/__СтандартныеПодсистемыСлужебныйПовтИсп.xml (100%) rename src/{ => cf}/CommonModules/__СтандартныеПодсистемыСлужебныйПовтИсп/Ext/Module.bsl (100%) rename src/{ => cf}/CommonModules/__СтроковыеФункцииКлиентСервер.xml (100%) rename src/{ => cf}/CommonModules/__СтроковыеФункцииКлиентСервер/Ext/Module.bsl (100%) rename src/{ => cf}/CommonModules/__СтроковыеФункцииСлужебныйКлиентСервер.xml (100%) rename src/{ => cf}/CommonModules/__СтроковыеФункцииСлужебныйКлиентСервер/Ext/Module.bsl (100%) rename src/{ => cf}/CommonModules/__СхемыЗапросов.xml (100%) rename src/{ => cf}/CommonModules/__СхемыЗапросов/Ext/Module.bsl (100%) rename src/{ => cf}/CommonModules/__ТипСоответствияОбъектовИБПереопределяемый.xml (100%) rename src/{ => cf}/CommonModules/__ТипСоответствияОбъектовИБПереопределяемый/Ext/Module.bsl (100%) rename src/{ => cf}/CommonPictures/__ПодсистемаУправлениеИнтеграциями.xml (100%) rename src/{ => cf}/CommonPictures/__ПодсистемаУправлениеИнтеграциями/Ext/Picture.xml (100%) rename src/{ => cf}/CommonPictures/__ПодсистемаУправлениеИнтеграциями/Ext/Picture/Picture.png (100%) rename src/{ => cf}/CommonPictures/__Реквизит.xml (100%) rename src/{ => cf}/CommonPictures/__Реквизит/Ext/Picture.xml (100%) rename src/{ => cf}/CommonPictures/__Реквизит/Ext/Picture/Picture.bmp (100%) rename src/{ => cf}/CommonPictures/__Реквизиты.xml (100%) rename src/{ => cf}/CommonPictures/__Реквизиты/Ext/Picture.xml (100%) rename src/{ => cf}/CommonPictures/__Реквизиты/Ext/Picture/Picture.bmp (100%) rename src/{ => cf}/CommonTemplates/__BSLEditor.xml (100%) rename src/{ => cf}/CommonTemplates/__BSLEditor/Ext/Template.bin (100%) rename src/{ => cf}/CommonTemplates/__JSONEditor.xml (100%) rename src/{ => cf}/CommonTemplates/__JSONEditor/Ext/Template.bin (100%) rename src/{ => cf}/CommonTemplates/__XMLEditor.xml (100%) rename src/{ => cf}/CommonTemplates/__XMLEditor/Ext/Template.bin (100%) rename src/{ => cf}/Configuration.xml (100%) rename src/{ => cf}/DefinedTypes/ТипыОбъектовСоответствийИБ.xml (100%) rename src/{ => cf}/Documents/ДемоРаботаСФормами.xml (100%) rename src/{ => cf}/Documents/ДемоРаботаСФормами/Forms/ФормаДокумента.xml (100%) rename src/{ => cf}/Documents/ДемоРаботаСФормами/Forms/ФормаДокумента/Ext/Form.xml (100%) rename src/{ => cf}/Documents/ДемоРаботаСФормами/Forms/ФормаДокумента/Ext/Form/Module.bsl (100%) rename src/{ => cf}/Enums/__КонтекстыВыполненияПользовательскихФункций.xml (100%) rename src/{ => cf}/Enums/__СозданОбновлен.xml (100%) rename src/{ => cf}/Enums/__СтатусыИнтеграции.xml (100%) rename src/{ => cf}/Enums/__ТипыJSON.xml (100%) rename src/{ => cf}/Enums/__ФорматыЗапросовИнтеграции.xml (100%) rename src/{ => cf}/EventSubscriptions/__ДокументыОбработкаЗаполнения.xml (100%) rename src/{ => cf}/EventSubscriptions/__ДокументыОбработкаПроведения.xml (100%) rename src/{ => cf}/EventSubscriptions/__ДокументыПередЗаписью.xml (100%) rename src/{ => cf}/EventSubscriptions/__ДокументыПриЗаписи.xml (100%) rename src/{ => cf}/EventSubscriptions/__ДокументыПриКопировании.xml (100%) rename src/{ => cf}/EventSubscriptions/__СправочникиОбработкаЗаполнения.xml (100%) rename src/{ => cf}/EventSubscriptions/__СправочникиПередЗаписью.xml (100%) rename src/{ => cf}/EventSubscriptions/__СправочникиПриЗаписи.xml (100%) rename src/{ => cf}/EventSubscriptions/__СправочникиПриКопировании.xml (100%) rename src/{ => cf}/InformationRegisters/__СоответствияОбъектовИБ.xml (100%) rename src/{ => cf}/InformationRegisters/__СоответствияОбъектовИБ/Ext/ManagerModule.bsl (100%) rename src/{ => cf}/InformationRegisters/__СоответствияОбъектовИБ/Forms/ФормаЗаписи.xml (100%) rename src/{ => cf}/InformationRegisters/__СоответствияОбъектовИБ/Forms/ФормаЗаписи/Ext/Form.xml (100%) rename src/{ => cf}/InformationRegisters/__СоответствияОбъектовИБ/Forms/ФормаЗаписи/Ext/Form/Module.bsl (100%) rename src/{ => cf}/InformationRegisters/__СоответствияОбъектовИБ/Forms/ФормаСписка.xml (100%) rename src/{ => cf}/InformationRegisters/__СоответствияОбъектовИБ/Forms/ФормаСписка/Ext/Form.xml (100%) rename src/{ => cf}/InformationRegisters/__СоответствияОбъектовИБ/Forms/ФормаСписка/Ext/Form/Module.bsl (100%) rename src/{ => cf}/Languages/English.xml (100%) rename src/{ => cf}/Languages/Русский.xml (100%) rename src/{ => cf}/Roles/__РедактированиеДокументаДемоКаркас.xml (100%) rename src/{ => cf}/Roles/__РедактированиеДокументаДемоКаркас/Ext/Rights.xml (100%) rename src/{ => cf}/Roles/__РедактированиеНастроекИнтеграции.xml (100%) rename src/{ => cf}/Roles/__РедактированиеНастроекИнтеграции/Ext/Rights.xml (100%) rename src/{ => cf}/Roles/__РедактированиеНастроекОтбораОбъектов.xml (100%) rename src/{ => cf}/Roles/__РедактированиеНастроекОтбораОбъектов/Ext/Rights.xml (100%) rename src/{ => cf}/Roles/__РедактированиеПланаВидовХарактеристикПредопределенныеЗначения.xml (100%) rename src/{ => cf}/Roles/__РедактированиеПланаВидовХарактеристикПредопределенныеЗначения/Ext/Rights.xml (100%) rename src/{ => cf}/Roles/__РедактированиеПользовательскихФункций.xml (100%) rename src/{ => cf}/Roles/__РедактированиеПользовательскихФункций/Ext/Rights.xml (100%) rename src/{ => cf}/Roles/__РедактированиеРегистраСведенийСоответствияОбъектовИБ.xml (100%) rename src/{ => cf}/Roles/__РедактированиеРегистраСведенийСоответствияОбъектовИБ/Ext/Rights.xml (100%) rename src/{ => cf}/Roles/__РедактированиеТиповСоответствияОбъектовИБ.xml (100%) rename src/{ => cf}/Roles/__РедактированиеТиповСоответствияОбъектовИБ/Ext/Rights.xml (100%) rename src/{ => cf}/Roles/__ЧтениеНастроекОтборовОбъектов.xml (100%) rename src/{ => cf}/Roles/__ЧтениеНастроекОтборовОбъектов/Ext/Rights.xml (100%) rename src/{ => cf}/Roles/__ЧтениеПланаВидовХарактеристикПредопределенныеЗначения.xml (100%) rename src/{ => cf}/Roles/__ЧтениеПланаВидовХарактеристикПредопределенныеЗначения/Ext/Rights.xml (100%) rename src/{ => cf}/Roles/__ЧтениеРегистраСведенийСоответствияОбъектовИБ.xml (100%) rename src/{ => cf}/Roles/__ЧтениеРегистраСведенийСоответствияОбъектовИБ/Ext/Rights.xml (100%) rename src/{ => cf}/Roles/__ЧтениеТиповСоответствияОбъектовИБ.xml (100%) rename src/{ => cf}/Roles/__ЧтениеТиповСоответствияОбъектовИБ/Ext/Rights.xml (100%) rename src/{ => cf}/Roles/АдминистраторСистемы.xml (100%) rename src/{ => cf}/Roles/АдминистраторСистемы/Ext/Rights.xml (100%) rename src/{ => cf}/Roles/ИнтерактивноеОткрытиеВнешнихОтчетовИОбработок.xml (100%) rename src/{ => cf}/Roles/ИнтерактивноеОткрытиеВнешнихОтчетовИОбработок/Ext/Rights.xml (100%) rename src/{ => cf}/Roles/ПолныеПрава.xml (100%) rename src/{ => cf}/Roles/ПолныеПрава/Ext/Rights.xml (100%) rename src/{ => cf}/ScheduledJobs/__ОчисткаИсторииИнтеграции.xml (100%) rename src/{ => cf}/ScheduledJobs/__ОчисткаИсторииИнтеграции/Ext/Schedule.xml (100%) rename src/{ => cf}/Subsystems/__ЗагрузкаИзТабличногоДокумента.xml (100%) rename src/{ => cf}/Subsystems/__МодификацияФорм.xml (100%) rename src/{ => cf}/Subsystems/__ОбщегоНазначения.xml (100%) rename src/{ => cf}/Subsystems/__ПодпискиНаСобытия.xml (100%) rename src/{ => cf}/Subsystems/__ПользовательскиеФункции.xml (100%) rename src/{ => cf}/Subsystems/__ПредопределенныеЗначения.xml (100%) rename src/{ => cf}/Subsystems/__СоответствиеОбъектовИБ.xml (100%) rename src/{ => cf}/Subsystems/__УправлениеИнтеграциями.xml (100%) create mode 100644 src/cfe/YAXUnit/CommonModules/Мокито.xml create mode 100644 src/cfe/YAXUnit/CommonModules/Мокито/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/МокитоОбучение.xml create mode 100644 src/cfe/YAXUnit/CommonModules/МокитоОбучение/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/МокитоПерехват.xml create mode 100644 src/cfe/YAXUnit/CommonModules/МокитоПерехват/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/МокитоПроверки.xml create mode 100644 src/cfe/YAXUnit/CommonModules/МокитоПроверки/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/МокитоСлужебный.xml create mode 100644 src/cfe/YAXUnit/CommonModules/МокитоСлужебный/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ОМ_КоннекторHTTP.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ОМ_КоннекторHTTP/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ОМ_ОбщегоНазаначенияСервер.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ОМ_ОбщегоНазаначенияСервер/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТАсинхроннаяОбработкаСлужебныйКлиент.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТАсинхроннаяОбработкаСлужебныйКлиент/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТЗапросы.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТЗапросы/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТЗапросыСлужебныйВызовСервера.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТЗапросыСлужебныйВызовСервера/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТЗапросыСлужебныйКлиентСервер.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТЗапросыСлужебныйКлиентСервер/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТИсключения.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТИсключения/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТИсполнительСлужебныйВызовСервера.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТИсполнительСлужебныйВызовСервера/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТИсполнительСлужебныйГлобальный.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТИсполнительСлужебныйГлобальный/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТИсполнительСлужебныйКлиент.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТИсполнительСлужебныйКлиент/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТИсполнительСлужебныйКлиентСервер.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТИсполнительСлужебныйКлиентСервер/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТКоллекции.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТКоллекции/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТКомпоненты.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТКомпоненты/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТКомпонентыСлужебныйВызовСервера.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТКомпонентыСлужебныйВызовСервера/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТКомпонентыСлужебныйКлиент.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТКомпонентыСлужебныйКлиент/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТКонструкторВариантов.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТКонструкторВариантов/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТКонструкторТестовыхДанныхСлужебный.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТКонструкторТестовыхДанныхСлужебный/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТКонтекстСлужебный.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТКонтекстСлужебный/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТКонтекстСлужебныйВызовСервера.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТКонтекстСлужебныйВызовСервера/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТКонтекстСлужебныйКлиент.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТКонтекстСлужебныйКлиент/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТКонтекстТеста.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТКонтекстТеста/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТЛогИсполненияТестаСлужебный.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТЛогИсполненияТестаСлужебный/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТЛогирование.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТЛогирование/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТЛогированиеСлужебный.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТЛогированиеСлужебный/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТЛогированиеСлужебныйВызовСервера.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТЛогированиеСлужебныйВызовСервера/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТЛокальСлужебный.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТЛокальСлужебный/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТМетаданные.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТМетаданные/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТМетаданныеСлужебный.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТМетаданныеСлужебный/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТМетаданныеСлужебныйВызовСервера.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТМетаданныеСлужебныйВызовСервера/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТМетаданныеСлужебныйПовтИсп.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТМетаданныеСлужебныйПовтИсп/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТМетодыСлужебный.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТМетодыСлужебный/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТНастройкиВыполнения.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТНастройкиВыполнения/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТОбщий.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТОбщий/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТОбщийСлужебныйВызовСервера.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТОбщийСлужебныйВызовСервера/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТОтчетAllureСлужебный.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТОтчетAllureСлужебный/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТОтчетJSONСлужебный.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТОтчетJSONСлужебный/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТОтчетJUnitСлужебный.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТОтчетJUnitСлужебный/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТОтчетСлужебный.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТОтчетСлужебный/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТПараметрыЗапускаСлужебный.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТПараметрыЗапускаСлужебный/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТПодражатель.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТПодражатель/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТПодражатель_Банки.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТПодражатель_Банки/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТПодражатель_Компании.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТПодражатель_Компании/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТПодражатель_Люди.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТПодражатель_Люди/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТПодражательСлужебный.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТПодражательСлужебный/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТПодражательСлужебныйВызовСервера.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТПодражательСлужебныйВызовСервера/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТПодражательСлужебныйПовтИсп.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТПодражательСлужебныйПовтИсп/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТПредикаты.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТПредикаты/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТПредикатыСлужебныйКлиентСервер.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТПредикатыСлужебныйКлиентСервер/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТПреобразованияСлужебный.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТПреобразованияСлужебный/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТПроверкиСлужебный.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТПроверкиСлужебный/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТРасширенияСлужебный.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТРасширенияСлужебный/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТРегистрацияОшибок.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТРегистрацияОшибок/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТРегистрацияОшибокСлужебный.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТРегистрацияОшибокСлужебный/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТСлужебныйПовторногоИспользования.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТСлужебныйПовторногоИспользования/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТСобытияСлужебный.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТСобытияСлужебный/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТСообщенияСлужебный.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТСообщенияСлужебный/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТСравнениеСлужебныйВызовСервера.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТСравнениеСлужебныйВызовСервера/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТСравнениеСлужебныйКлиентСервер.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТСравнениеСлужебныйКлиентСервер/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТСтроки.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТСтроки/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТТестовыеДанные.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТТестовыеДанные/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТТестовыеДанныеСлужебный.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТТестовыеДанныеСлужебный/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТТестовыеДанныеСлужебныйВызовСервера.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТТестовыеДанныеСлужебныйВызовСервера/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТТестовыеДанныеСлужебныйТаблицыЗначений.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТТестовыеДанныеСлужебныйТаблицыЗначений/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТТесты.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТТесты/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТТестыСлужебный.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТТестыСлужебный/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТТипыДанныхСлужебный.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТТипыДанныхСлужебный/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТУтверждения.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТУтверждения/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТУтвержденияИБ.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТУтвержденияИБ/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТФабрика.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТФабрика/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТФабрикаСлужебный.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТФабрикаСлужебный/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТФайлы.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТФайлы/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТФильтрацияСлужебный.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТФильтрацияСлужебный/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТЧитательСлужебный.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТЧитательСлужебный/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТЧитательСлужебныйВызовСервера.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТЧитательСлужебныйВызовСервера/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТест.xml create mode 100644 src/cfe/YAXUnit/CommonModules/ЮТест/Ext/Module.bsl create mode 100644 src/cfe/YAXUnit/CommonPictures/ЮТЗапустить.xml create mode 100644 src/cfe/YAXUnit/CommonPictures/ЮТЗапустить/Ext/Picture.xml create mode 100644 src/cfe/YAXUnit/CommonPictures/ЮТЗапустить/Ext/Picture/Picture.svg create mode 100644 src/cfe/YAXUnit/CommonPictures/ЮТНеизвестный.xml create mode 100644 src/cfe/YAXUnit/CommonPictures/ЮТНеизвестный/Ext/Picture.xml create mode 100644 src/cfe/YAXUnit/CommonPictures/ЮТНеизвестный/Ext/Picture/Picture.svg create mode 100644 src/cfe/YAXUnit/CommonPictures/ЮТОшибка.xml create mode 100644 src/cfe/YAXUnit/CommonPictures/ЮТОшибка/Ext/Picture.xml create mode 100644 src/cfe/YAXUnit/CommonPictures/ЮТОшибка/Ext/Picture/Picture.svg create mode 100644 src/cfe/YAXUnit/CommonPictures/ЮТПерезапуститьУпавшие.xml create mode 100644 src/cfe/YAXUnit/CommonPictures/ЮТПерезапуститьУпавшие/Ext/Picture.xml create mode 100644 src/cfe/YAXUnit/CommonPictures/ЮТПерезапуститьУпавшие/Ext/Picture/Picture.svg create mode 100644 src/cfe/YAXUnit/CommonPictures/ЮТПодсистема.xml create mode 100644 src/cfe/YAXUnit/CommonPictures/ЮТПодсистема/Ext/Picture.xml create mode 100644 src/cfe/YAXUnit/CommonPictures/ЮТПодсистема/Ext/Picture/Picture.png create mode 100644 src/cfe/YAXUnit/CommonPictures/ЮТПропущен.xml create mode 100644 src/cfe/YAXUnit/CommonPictures/ЮТПропущен/Ext/Picture.xml create mode 100644 src/cfe/YAXUnit/CommonPictures/ЮТПропущен/Ext/Picture/Picture.svg create mode 100644 src/cfe/YAXUnit/CommonPictures/ЮТСравнить.xml create mode 100644 src/cfe/YAXUnit/CommonPictures/ЮТСравнить/Ext/Picture.xml create mode 100644 src/cfe/YAXUnit/CommonPictures/ЮТСравнить/Ext/Picture/Picture.svg create mode 100644 src/cfe/YAXUnit/CommonPictures/ЮТУпал.xml create mode 100644 src/cfe/YAXUnit/CommonPictures/ЮТУпал/Ext/Picture.xml create mode 100644 src/cfe/YAXUnit/CommonPictures/ЮТУпал/Ext/Picture/Picture.svg create mode 100644 src/cfe/YAXUnit/CommonPictures/ЮТУспешно.xml create mode 100644 src/cfe/YAXUnit/CommonPictures/ЮТУспешно/Ext/Picture.xml create mode 100644 src/cfe/YAXUnit/CommonPictures/ЮТУспешно/Ext/Picture/Picture.svg create mode 100644 src/cfe/YAXUnit/CommonPictures/ЮТЭлементыТестов.xml create mode 100644 src/cfe/YAXUnit/CommonPictures/ЮТЭлементыТестов/Ext/Picture.xml create mode 100644 src/cfe/YAXUnit/CommonPictures/ЮТЭлементыТестов/Ext/Picture/Picture.svg create mode 100644 src/cfe/YAXUnit/CommonTemplates/ЮТRegEx1CAddin.xml create mode 100644 src/cfe/YAXUnit/CommonTemplates/ЮТRegEx1CAddin/Ext/Template.bin create mode 100644 src/cfe/YAXUnit/CommonTemplates/ЮТYaxUnitAddIn.xml create mode 100644 src/cfe/YAXUnit/CommonTemplates/ЮТYaxUnitAddIn/Ext/Template.bin create mode 100644 src/cfe/YAXUnit/CommonTemplates/ЮТ_СловарьПодражателя_Компании_Наименования_ru.xml create mode 100644 src/cfe/YAXUnit/CommonTemplates/ЮТ_СловарьПодражателя_Компании_Наименования_ru/Ext/Template.txt create mode 100644 src/cfe/YAXUnit/CommonTemplates/ЮТ_СловарьПодражателя_Компании_ПрефиксыНаименований_ru.xml create mode 100644 src/cfe/YAXUnit/CommonTemplates/ЮТ_СловарьПодражателя_Компании_ПрефиксыНаименований_ru/Ext/Template.txt create mode 100644 src/cfe/YAXUnit/CommonTemplates/ЮТ_СловарьПодражателя_Люди_ЖенскиеИмена_ru.xml create mode 100644 src/cfe/YAXUnit/CommonTemplates/ЮТ_СловарьПодражателя_Люди_ЖенскиеИмена_ru/Ext/Template.txt create mode 100644 src/cfe/YAXUnit/CommonTemplates/ЮТ_СловарьПодражателя_Люди_ЖенскиеОтчества_ru.xml create mode 100644 src/cfe/YAXUnit/CommonTemplates/ЮТ_СловарьПодражателя_Люди_ЖенскиеОтчества_ru/Ext/Template.txt create mode 100644 src/cfe/YAXUnit/CommonTemplates/ЮТ_СловарьПодражателя_Люди_ЖенскиеФамилии_ru.xml create mode 100644 src/cfe/YAXUnit/CommonTemplates/ЮТ_СловарьПодражателя_Люди_ЖенскиеФамилии_ru/Ext/Template.txt create mode 100644 src/cfe/YAXUnit/CommonTemplates/ЮТ_СловарьПодражателя_Люди_МужскиеИмена_ru.xml create mode 100644 src/cfe/YAXUnit/CommonTemplates/ЮТ_СловарьПодражателя_Люди_МужскиеИмена_ru/Ext/Template.txt create mode 100644 src/cfe/YAXUnit/CommonTemplates/ЮТ_СловарьПодражателя_Люди_МужскиеОтчества_ru.xml create mode 100644 src/cfe/YAXUnit/CommonTemplates/ЮТ_СловарьПодражателя_Люди_МужскиеОтчества_ru/Ext/Template.txt create mode 100644 src/cfe/YAXUnit/CommonTemplates/ЮТ_СловарьПодражателя_Люди_МужскиеФамилии_ru.xml create mode 100644 src/cfe/YAXUnit/CommonTemplates/ЮТ_СловарьПодражателя_Люди_МужскиеФамилии_ru/Ext/Template.txt create mode 100644 src/cfe/YAXUnit/CommonTemplates/ЮТИнформацияОбОшибке.xml create mode 100644 src/cfe/YAXUnit/CommonTemplates/ЮТИнформацияОбОшибке/Ext/Template.txt create mode 100644 src/cfe/YAXUnit/CommonTemplates/ЮТОписаниеМетаданных.xml create mode 100644 src/cfe/YAXUnit/CommonTemplates/ЮТОписаниеМетаданных/Ext/Template.txt create mode 100644 src/cfe/YAXUnit/Configuration.xml create mode 100644 src/cfe/YAXUnit/DataProcessors/ЮТHTTPServiceRequest.xml create mode 100644 src/cfe/YAXUnit/DataProcessors/ЮТHTTPServiceRequest/Ext/ObjectModule.bsl create mode 100644 src/cfe/YAXUnit/DataProcessors/ЮТHTTPСервисЗапрос.xml create mode 100644 src/cfe/YAXUnit/DataProcessors/ЮТHTTPСервисЗапрос/Ext/ObjectModule.bsl create mode 100644 src/cfe/YAXUnit/DataProcessors/ЮТRecordSet.xml create mode 100644 src/cfe/YAXUnit/DataProcessors/ЮТRecordSet/Ext/ObjectModule.bsl create mode 100644 src/cfe/YAXUnit/DataProcessors/ЮТКонструкторОбъектаXDTO.xml create mode 100644 src/cfe/YAXUnit/DataProcessors/ЮТКонструкторОбъектаXDTO/Ext/ObjectModule.bsl create mode 100644 src/cfe/YAXUnit/DataProcessors/ЮТКонструкторТестовыхДанных.xml create mode 100644 src/cfe/YAXUnit/DataProcessors/ЮТКонструкторТестовыхДанных/Ext/ObjectModule.bsl create mode 100644 src/cfe/YAXUnit/DataProcessors/ЮТКонструкторТестовыхДанных/Forms/КлиентскийКонструктор.xml create mode 100644 src/cfe/YAXUnit/DataProcessors/ЮТКонструкторТестовыхДанных/Forms/КлиентскийКонструктор/Ext/Form.xml create mode 100644 src/cfe/YAXUnit/DataProcessors/ЮТКонструкторТестовыхДанных/Forms/КлиентскийКонструктор/Ext/Form/Module.bsl create mode 100644 src/cfe/YAXUnit/DataProcessors/ЮТЮнитТесты.xml create mode 100644 src/cfe/YAXUnit/DataProcessors/ЮТЮнитТесты/Commands/ЗапускТестов/Ext/CommandModule.bsl create mode 100644 src/cfe/YAXUnit/DataProcessors/ЮТЮнитТесты/Commands/СформироватьНастройкиТестирования/Ext/CommandModule.bsl create mode 100644 src/cfe/YAXUnit/DataProcessors/ЮТЮнитТесты/Forms/Основная.xml create mode 100644 src/cfe/YAXUnit/DataProcessors/ЮТЮнитТесты/Forms/Основная/Ext/Form.xml create mode 100644 src/cfe/YAXUnit/DataProcessors/ЮТЮнитТесты/Forms/Основная/Ext/Form/Module.bsl create mode 100644 src/cfe/YAXUnit/DataProcessors/ЮТЮнитТесты/Forms/СозданиеНастройки.xml create mode 100644 src/cfe/YAXUnit/DataProcessors/ЮТЮнитТесты/Forms/СозданиеНастройки/Ext/Form.xml create mode 100644 src/cfe/YAXUnit/DataProcessors/ЮТЮнитТесты/Forms/СозданиеНастройки/Ext/Form/Module.bsl create mode 100644 src/cfe/YAXUnit/DataProcessors/ЮТЮнитТесты/Forms/Сравнение.xml create mode 100644 src/cfe/YAXUnit/DataProcessors/ЮТЮнитТесты/Forms/Сравнение/Ext/Form.xml create mode 100644 src/cfe/YAXUnit/DataProcessors/ЮТЮнитТесты/Forms/Сравнение/Ext/Form/Module.bsl create mode 100644 src/cfe/YAXUnit/DataProcessors/ЮТЮнитТесты/Templates/Сравнение.xml create mode 100644 src/cfe/YAXUnit/DataProcessors/ЮТЮнитТесты/Templates/Сравнение/Ext/Template.txt create mode 100644 src/cfe/YAXUnit/DataProcessors/ЮТЮнитТесты/Templates/СравнениеOld.xml create mode 100644 src/cfe/YAXUnit/DataProcessors/ЮТЮнитТесты/Templates/СравнениеOld/Ext/Template.txt create mode 100644 src/cfe/YAXUnit/Ext/ManagedApplicationModule.bsl create mode 100644 src/cfe/YAXUnit/Ext/OrdinaryApplicationModule.bsl create mode 100644 src/cfe/YAXUnit/Languages/Русский.xml create mode 100644 src/cfe/YAXUnit/Subsystems/ЮТДвижок.xml create mode 100644 src/cfe/YAXUnit/Subsystems/ЮТДвижок/Subsystems/ЮТИсполнитель.xml create mode 100644 src/cfe/YAXUnit/Subsystems/ЮТДвижок/Subsystems/ЮТКонтекст.xml create mode 100644 src/cfe/YAXUnit/Subsystems/ЮТДвижок/Subsystems/ЮТМокирование.xml create mode 100644 src/cfe/YAXUnit/Subsystems/ЮТДвижок/Subsystems/ЮТСервис.xml create mode 100644 src/cfe/YAXUnit/Subsystems/ЮТДвижок/Subsystems/ЮТТестовыеДанные.xml create mode 100644 src/cfe/YAXUnit/Subsystems/ЮТДвижок/Subsystems/ЮТТестовыеДанные/Subsystems/ЮТПодражатель.xml create mode 100644 src/cfe/YAXUnit/Subsystems/ЮТДвижок/Subsystems/ЮТУтверждения.xml create mode 100644 src/cfe/YAXUnit/Subsystems/ЮТДинамическиПодключаемые.xml create mode 100644 src/cfe/YAXUnit/Subsystems/ЮТДинамическиПодключаемые/Subsystems/ЮТОбработчикиСобытий.xml create mode 100644 src/cfe/YAXUnit/Subsystems/ЮТДинамическиПодключаемые/Subsystems/ЮТФормированиеОтчета.xml create mode 100644 src/cfe/YAXUnit/Subsystems/ЮТПубличный.xml create mode 100644 tools/yaxunit.json diff --git a/.gitignore b/.gitignore index 1aa2856..af69900 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ -src/ConfigDumpInfo.xml -src/dumplist.txt +ConfigDumpInfo.xml +dumplist.txt .vscode /.metadata/ -/.scannerwork/ \ No newline at end of file +/.scannerwork/ diff --git a/README.md b/README.md index 8f1e192..4459e14 100644 --- a/README.md +++ b/README.md @@ -32,5 +32,11 @@ ## Информация для контрибьюторов +### Версия платформы и режим совместимости + > Разработка ведется на версии 8.3.23 > Режим совместимости 8.3.18 + +### Руководство контрибьютора + +1. [Руководство по написанию юнит-тестов YaXUnit](docs/РуководствоПоНаписаниюТестовYAxUnit.md) diff --git a/docs/РуководствоПоНаписаниюТестовYAxUnit.md b/docs/РуководствоПоНаписаниюТестовYAxUnit.md new file mode 100644 index 0000000..ca2ad49 --- /dev/null +++ b/docs/РуководствоПоНаписаниюТестовYAxUnit.md @@ -0,0 +1,86 @@ +# Руководство по написанию тестов YAxUnit + +## Шаг 1: Клонирование репозитория + +Для начала работы вам необходимо клонировать репозиторий с GitHub. Вы можете сделать это, выполнив следующую команду в Git: + +```bash +git clone https://github.com/firstBitSportivnaya/PSSL.git +``` + +## Шаг 2: Загрузка конфигурации +После клонирования репозитория загрузите конфигурацию в информационную базу из каталога: +```bash +PSSL/src/cf/ +``` +## Шаг 3: Добавление расширения конфигурации +Далее необходимо добавить расширение конфигурации YAxUnit, используйте файлы из следующего каталога: +```bash +PSSL/src/cfe/YAXUnit +``` +После добавления расширения в режиме 1С:Предприятие должна появиться панель управления YAxUnit, которая отображается в виде подсистемы. + +## Шаг 4: Создание тестов +### Определение тестируемой функции +Допустим в вашей конфигурации есть общий модуль **__ОбщегоНазначенияВспомогательныеФункции** в котором есть функция определения четности числа: + +```1C +Функция ЧетноеЧисло(Число) Экспорт + Возврат Число % 2 = 0; +КонецФункции +``` +В данном примере рассмотрим написание тестов для этой функции. + +### Составление тестового набора +Для начала необходимо составить тестовый набор для проверки функции, стараясь покрыть пограничные случаи: +| Число | Результат | +|-------|-------------| +| 2 | Четное | +| 1 | Нечетное | +| 0 | Четное | +| -1 | Нечетное | +| -2 | Четное | +| 100 | Четное | +| 99 | Нечетное | + +### Создание модуля для тестов +Создайте новый модуль в расширении YAxUnit, который принято называть по названию объекта, в котором находится тестируемая функция. Для нашего случая это будет модуль **ОМ__ОбщегоНазначенияВспомогательныеФункции**. + +### Написание теста +Теперь напишем сам тест, для этого внутри **ОМ__ОбщегоНазначенияВспомогательныеФункции** создаем процедуру **ИсполняемыеСценарии()**: +```1C +Процедура ИсполняемыеСценарии() Экспорт + // Создание группы тестов + ЮТТесты.ДобавитьТестовыйНабор("Проверка функции ЧетноеЧисло") + // Добавление конкретного теста в группу + .ДобавитьТест("ТестЧетноеЧисло") + // Передача параметров в тест + .СПараметрами(Новый Структура("Число, ОжидаемыйРезультат", 2, Истина)) + .СПараметрами(Новый Структура("Число, ОжидаемыйРезультат", 1, Ложь)) + .СПараметрами(Новый Структура("Число, ОжидаемыйРезультат", 0, Истина)) + .СПараметрами(Новый Структура("Число, ОжидаемыйРезультат", -1, Ложь)) + .СПараметрами(Новый Структура("Число, ОжидаемыйРезультат", -2, Истина)) + .СПараметрами(Новый Структура("Число, ОжидаемыйРезультат", 100, Истина)) + .СПараметрами(Новый Структура("Число, ОжидаемыйРезультат", 99, Ложь)); +КонецПроцедуры +``` +#### Структура процедуры ИсполняемыеСценарии() +Процедура обычно содержит вызовы методов для добавления тестов. Основной метод — **ДобавитьТестовыйНабор()**, который создает группу тестов. В каждую группу затем добавляются конкретные тесты с помощью метода **ДобавитьТест()**. Эти тесты могут иметь параметры, задаваемые через метод **СПараметрами()**. + +#### Написание самого теста +Сам тест реализуется в отдельной процедуре, которая вызывается из **ИсполняемыеСценарии()** через **ДобавитьТест()**. В этой процедуре вы описываете логику тестирования. + +Пример процедуры теста: +```1C +Процедура ТестЧетноеЧисло(Параметры) Экспорт + // Вызов тестируемой функции + Результат = __ОбщегоНазначенияВспомогательныеФункции.ЧетноеЧисло(Параметры.Число); + + // Проверка результата + ЮТест.ОжидаетЧто(Результат).Равно(Параметры.ОжидаемыйРезультат); +КонецПроцедуры +``` + Теперь при запуске конфигурации в режиме 1С:Предприятие, в подсистеме YAxUnit должен отобразиться наш тест. + Запускаем тест и видим результат его работы. + +Полную и исчерпывающую информацию по работе с расширением можно найти в документации [YAXUnit](https://bia-technologies.github.io/yaxunit/). diff --git a/features/Проверка пометки на удаление.feature b/features/Проверка пометки на удаление.feature new file mode 100644 index 0000000..e2925a3 --- /dev/null +++ b/features/Проверка пометки на удаление.feature @@ -0,0 +1,29 @@ +#language: ru + +@tree + +Функционал: проверка установки пометки удаления + +Контекст: + Дано Я запускаю сценарий открытия TestClient или подключаю уже существующий + +Сценарий: Проверка установки пометки удаления для элементов справочника Тип соответствия объектов ИБ +* Создание элемента + И В командном интерфейсе я выбираю 'Соответствие объектов ИБ' 'Тип соответствия объектов ИБ' + Тогда открылось окно 'Тип соответствия объектов ИБ' + И я нажимаю на кнопку с именем 'ФормаСоздать' + Тогда открылось окно 'Тип соответствия объектов ИБ (создание)' + И в поле с именем 'Наименование' я ввожу текст 'ВА_Тест' + И я нажимаю на кнопку с именем 'ФормаЗаписатьИЗакрыть' +* Установка пометки + И в таблице 'Список' я выделяю все строки + И я выбираю пункт контекстного меню с именем 'СписокКонтекстноеМенюУстановитьПометкуУдаления' на элементе формы с именем "Список" + Тогда открылось окно '1С:Предприятие' + И я нажимаю на кнопку с именем 'Button0' +* Снятие пометки + Когда открылось окно 'Тип соответствия объектов ИБ' + И в таблице 'Список' я выделяю все строки + И я выбираю пункт контекстного меню с именем 'СписокКонтекстноеМенюУстановитьПометкуУдаления' на элементе формы с именем "Список" + Тогда открылось окно '1С:Предприятие' + И я нажимаю на кнопку с именем 'Button0' + \ No newline at end of file diff --git a/features/Создание элемента справочника.feature b/features/Создание элемента справочника.feature new file mode 100644 index 0000000..37eb3b4 --- /dev/null +++ b/features/Создание элемента справочника.feature @@ -0,0 +1,30 @@ +#language: ru + +@tree + +Функционал: ввод данных + +Контекст: + Дано Я запускаю сценарий открытия TestClient или подключаю уже существующий + +Сценарий: Создание элемента справочника Тип соответствия объектов ИБ +* Создание элемента + И В командном интерфейсе я выбираю 'Соответствие объектов ИБ' 'Тип соответствия объектов ИБ' + Тогда открылось окно 'Тип соответствия объектов ИБ' + И я нажимаю на кнопку с именем 'ФормаСоздать' + Тогда открылось окно 'Тип соответствия объектов ИБ (создание)' + И в поле с именем 'Наименование' я ввожу текст 'ВА - Тест' + И в поле с именем 'ИдентификаторНастройки' я ввожу текст 'ВА - Тест' + И я нажимаю на кнопку с именем 'ФормаЗаписатьИЗакрыть' + И я жду закрытия окна 'Тип соответствия объектов ИБ (создание) *' в течение 20 секунд +* Проверка создания + Когда открылось окно 'Тип соответствия объектов ИБ' + И я нажимаю на кнопку с именем 'ФормаНайти' + Тогда открылось окно 'Найти' + И я меняю значение переключателя с именем 'CompareType' на 'По точному совпадению' + И я нажимаю на кнопку с именем 'Find' + Тогда открылось окно 'Тип соответствия объектов ИБ' + И в таблице "Список" я выбираю текущую строку + Тогда открылось окно 'ВА - Тест (Тип соответствия объектов ИБ)' + И Я закрываю окно 'ВА - Тест (Тип соответствия объектов ИБ)' + \ No newline at end of file diff --git a/jobConfiguration.json b/jobConfiguration.json index 2010f91..e628070 100644 --- a/jobConfiguration.json +++ b/jobConfiguration.json @@ -1,35 +1,33 @@ { - "$schema": "https://raw.githubusercontent.com/firstBitMarksistskaya/jenkins-lib/feature-telegram/resources/schema.json", + "$schema": "https://raw.githubusercontent.com/firstBitMarksistskaya/jenkins-lib/develop/resources/schema.json", "stages": { "initSteps": true, "syntaxCheck": true, "smoke": true, - "sonarqube": true, - "telegram": true - }, - "timeout": { - "smoke": 300, - "bdd": 180, - "createInfoBase": 120, - "designerToEdtFormatTransformation": 120, - "edtToDesignerFormatTransformation": 120, - "edtValidate": 300, - "initInfoBase": 120, - "resultTransformation": 60, - "sonarqube": 150, - "syntaxCheck": 300, - "zipInfoBase": 120 + "yaxunit": true, + "telegram": true, + "bdd": true }, "sourceFormat": "designer", - "srcDir": "src", - "resultsTransform": { - "removeSupport": false - }, - "sonarqube": { - "waitForQualityGate": true - }, + "srcDir": "src/cf", "initInfobase": { - "initMethod": "fromSource" + "initMethod": "fromSource", + "extensions": [ + { + "name": "YAXUnit", + "initMethod": "fromSource", + "path": "src/cfe/YAXUnit", + "stages": ["yaxunit"] + } + ] + }, + "smoke": { + "publishToAllureReport": false, + "publishToJUnitReport": true + }, + "yaxunit": { + "publishToAllureReport": false, + "publishToJUnitReport": true }, "notifications": { "telegram": { diff --git a/sonar-project.properties b/sonar-project.properties index 38db2fa..b37c267 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -11,7 +11,7 @@ sonar.projectName=1C: Project SubSystems Library sonar.projectVersion=1.0 # относительный или абсолютный путь к каталогу с исходными кодом -sonar.sources=src +sonar.sources=src/cf # кодировка sonar.sourceEncoding=UTF-8 @@ -27,4 +27,4 @@ sonar.scm.exclusions.disabled=true # для Git sonar.scm.enabled=true -sonar.scm.provider=git +sonar.scm.provider=git \ No newline at end of file diff --git a/src/Catalogs/__ИнтегрируемыеСистемы.xml b/src/cf/Catalogs/__ИнтегрируемыеСистемы.xml similarity index 100% rename from src/Catalogs/__ИнтегрируемыеСистемы.xml rename to src/cf/Catalogs/__ИнтегрируемыеСистемы.xml diff --git a/src/Catalogs/__ИнтегрируемыеСистемы/Ext/ManagerModule.bsl b/src/cf/Catalogs/__ИнтегрируемыеСистемы/Ext/ManagerModule.bsl similarity index 100% rename from src/Catalogs/__ИнтегрируемыеСистемы/Ext/ManagerModule.bsl rename to src/cf/Catalogs/__ИнтегрируемыеСистемы/Ext/ManagerModule.bsl diff --git a/src/Catalogs/__ИнтегрируемыеСистемы/Forms/ФормаСписка.xml b/src/cf/Catalogs/__ИнтегрируемыеСистемы/Forms/ФормаСписка.xml similarity index 100% rename from src/Catalogs/__ИнтегрируемыеСистемы/Forms/ФормаСписка.xml rename to src/cf/Catalogs/__ИнтегрируемыеСистемы/Forms/ФормаСписка.xml diff --git a/src/Catalogs/__ИнтегрируемыеСистемы/Forms/ФормаСписка/Ext/Form.xml b/src/cf/Catalogs/__ИнтегрируемыеСистемы/Forms/ФормаСписка/Ext/Form.xml similarity index 100% rename from src/Catalogs/__ИнтегрируемыеСистемы/Forms/ФормаСписка/Ext/Form.xml rename to src/cf/Catalogs/__ИнтегрируемыеСистемы/Forms/ФормаСписка/Ext/Form.xml diff --git a/src/Catalogs/__ИнтегрируемыеСистемы/Forms/ФормаСписка/Ext/Form/Module.bsl b/src/cf/Catalogs/__ИнтегрируемыеСистемы/Forms/ФормаСписка/Ext/Form/Module.bsl similarity index 100% rename from src/Catalogs/__ИнтегрируемыеСистемы/Forms/ФормаСписка/Ext/Form/Module.bsl rename to src/cf/Catalogs/__ИнтегрируемыеСистемы/Forms/ФормаСписка/Ext/Form/Module.bsl diff --git a/src/Catalogs/__ИнтегрируемыеСистемы/Forms/ФормаЭлемента.xml b/src/cf/Catalogs/__ИнтегрируемыеСистемы/Forms/ФормаЭлемента.xml similarity index 100% rename from src/Catalogs/__ИнтегрируемыеСистемы/Forms/ФормаЭлемента.xml rename to src/cf/Catalogs/__ИнтегрируемыеСистемы/Forms/ФормаЭлемента.xml diff --git a/src/Catalogs/__ИнтегрируемыеСистемы/Forms/ФормаЭлемента/Ext/Form.xml b/src/cf/Catalogs/__ИнтегрируемыеСистемы/Forms/ФормаЭлемента/Ext/Form.xml similarity index 100% rename from src/Catalogs/__ИнтегрируемыеСистемы/Forms/ФормаЭлемента/Ext/Form.xml rename to src/cf/Catalogs/__ИнтегрируемыеСистемы/Forms/ФормаЭлемента/Ext/Form.xml diff --git a/src/Catalogs/__ИсторияИнтеграции.xml b/src/cf/Catalogs/__ИсторияИнтеграции.xml similarity index 100% rename from src/Catalogs/__ИсторияИнтеграции.xml rename to src/cf/Catalogs/__ИсторияИнтеграции.xml diff --git a/src/Catalogs/__ИсторияИнтеграции/Ext/ManagerModule.bsl b/src/cf/Catalogs/__ИсторияИнтеграции/Ext/ManagerModule.bsl similarity index 100% rename from src/Catalogs/__ИсторияИнтеграции/Ext/ManagerModule.bsl rename to src/cf/Catalogs/__ИсторияИнтеграции/Ext/ManagerModule.bsl diff --git a/src/Catalogs/__ИсторияИнтеграции/Ext/ObjectModule.bsl b/src/cf/Catalogs/__ИсторияИнтеграции/Ext/ObjectModule.bsl similarity index 100% rename from src/Catalogs/__ИсторияИнтеграции/Ext/ObjectModule.bsl rename to src/cf/Catalogs/__ИсторияИнтеграции/Ext/ObjectModule.bsl diff --git a/src/Catalogs/__ИсторияИнтеграции/Forms/ФормаСписка.xml b/src/cf/Catalogs/__ИсторияИнтеграции/Forms/ФормаСписка.xml similarity index 100% rename from src/Catalogs/__ИсторияИнтеграции/Forms/ФормаСписка.xml rename to src/cf/Catalogs/__ИсторияИнтеграции/Forms/ФормаСписка.xml diff --git a/src/Catalogs/__ИсторияИнтеграции/Forms/ФормаСписка/Ext/Form.xml b/src/cf/Catalogs/__ИсторияИнтеграции/Forms/ФормаСписка/Ext/Form.xml similarity index 100% rename from src/Catalogs/__ИсторияИнтеграции/Forms/ФормаСписка/Ext/Form.xml rename to src/cf/Catalogs/__ИсторияИнтеграции/Forms/ФормаСписка/Ext/Form.xml diff --git a/src/Catalogs/__ИсторияИнтеграции/Forms/ФормаСписка/Ext/Form/Module.bsl b/src/cf/Catalogs/__ИсторияИнтеграции/Forms/ФормаСписка/Ext/Form/Module.bsl similarity index 100% rename from src/Catalogs/__ИсторияИнтеграции/Forms/ФормаСписка/Ext/Form/Module.bsl rename to src/cf/Catalogs/__ИсторияИнтеграции/Forms/ФормаСписка/Ext/Form/Module.bsl diff --git a/src/Catalogs/__ИсторияИнтеграции/Forms/ФормаЭлемента.xml b/src/cf/Catalogs/__ИсторияИнтеграции/Forms/ФормаЭлемента.xml similarity index 100% rename from src/Catalogs/__ИсторияИнтеграции/Forms/ФормаЭлемента.xml rename to src/cf/Catalogs/__ИсторияИнтеграции/Forms/ФормаЭлемента.xml diff --git a/src/Catalogs/__ИсторияИнтеграции/Forms/ФормаЭлемента/Ext/Form.xml b/src/cf/Catalogs/__ИсторияИнтеграции/Forms/ФормаЭлемента/Ext/Form.xml similarity index 100% rename from src/Catalogs/__ИсторияИнтеграции/Forms/ФормаЭлемента/Ext/Form.xml rename to src/cf/Catalogs/__ИсторияИнтеграции/Forms/ФормаЭлемента/Ext/Form.xml diff --git a/src/Catalogs/__ИсторияИнтеграции/Forms/ФормаЭлемента/Ext/Form/Module.bsl b/src/cf/Catalogs/__ИсторияИнтеграции/Forms/ФормаЭлемента/Ext/Form/Module.bsl similarity index 100% rename from src/Catalogs/__ИсторияИнтеграции/Forms/ФормаЭлемента/Ext/Form/Module.bsl rename to src/cf/Catalogs/__ИсторияИнтеграции/Forms/ФормаЭлемента/Ext/Form/Module.bsl diff --git a/src/Catalogs/__МетодыИнтеграции.xml b/src/cf/Catalogs/__МетодыИнтеграции.xml similarity index 100% rename from src/Catalogs/__МетодыИнтеграции.xml rename to src/cf/Catalogs/__МетодыИнтеграции.xml diff --git a/src/Catalogs/__МетодыИнтеграции/Ext/ManagerModule.bsl b/src/cf/Catalogs/__МетодыИнтеграции/Ext/ManagerModule.bsl similarity index 100% rename from src/Catalogs/__МетодыИнтеграции/Ext/ManagerModule.bsl rename to src/cf/Catalogs/__МетодыИнтеграции/Ext/ManagerModule.bsl diff --git a/src/Catalogs/__МетодыИнтеграции/Forms/ФормаСписка.xml b/src/cf/Catalogs/__МетодыИнтеграции/Forms/ФормаСписка.xml similarity index 100% rename from src/Catalogs/__МетодыИнтеграции/Forms/ФормаСписка.xml rename to src/cf/Catalogs/__МетодыИнтеграции/Forms/ФормаСписка.xml diff --git a/src/Catalogs/__МетодыИнтеграции/Forms/ФормаСписка/Ext/Form.xml b/src/cf/Catalogs/__МетодыИнтеграции/Forms/ФормаСписка/Ext/Form.xml similarity index 100% rename from src/Catalogs/__МетодыИнтеграции/Forms/ФормаСписка/Ext/Form.xml rename to src/cf/Catalogs/__МетодыИнтеграции/Forms/ФормаСписка/Ext/Form.xml diff --git a/src/Catalogs/__МетодыИнтеграции/Forms/ФормаСписка/Ext/Form/Module.bsl b/src/cf/Catalogs/__МетодыИнтеграции/Forms/ФормаСписка/Ext/Form/Module.bsl similarity index 100% rename from src/Catalogs/__МетодыИнтеграции/Forms/ФормаСписка/Ext/Form/Module.bsl rename to src/cf/Catalogs/__МетодыИнтеграции/Forms/ФормаСписка/Ext/Form/Module.bsl diff --git a/src/Catalogs/__МетодыИнтеграции/Forms/ФормаЭлемента.xml b/src/cf/Catalogs/__МетодыИнтеграции/Forms/ФормаЭлемента.xml similarity index 100% rename from src/Catalogs/__МетодыИнтеграции/Forms/ФормаЭлемента.xml rename to src/cf/Catalogs/__МетодыИнтеграции/Forms/ФормаЭлемента.xml diff --git a/src/Catalogs/__МетодыИнтеграции/Forms/ФормаЭлемента/Ext/Form.xml b/src/cf/Catalogs/__МетодыИнтеграции/Forms/ФормаЭлемента/Ext/Form.xml similarity index 100% rename from src/Catalogs/__МетодыИнтеграции/Forms/ФормаЭлемента/Ext/Form.xml rename to src/cf/Catalogs/__МетодыИнтеграции/Forms/ФормаЭлемента/Ext/Form.xml diff --git a/src/Catalogs/__НастройкиИнтеграции.xml b/src/cf/Catalogs/__НастройкиИнтеграции.xml similarity index 100% rename from src/Catalogs/__НастройкиИнтеграции.xml rename to src/cf/Catalogs/__НастройкиИнтеграции.xml diff --git a/src/Catalogs/__НастройкиИнтеграции/Ext/ManagerModule.bsl b/src/cf/Catalogs/__НастройкиИнтеграции/Ext/ManagerModule.bsl similarity index 100% rename from src/Catalogs/__НастройкиИнтеграции/Ext/ManagerModule.bsl rename to src/cf/Catalogs/__НастройкиИнтеграции/Ext/ManagerModule.bsl diff --git a/src/Catalogs/__НастройкиИнтеграции/Forms/ФормаСписка.xml b/src/cf/Catalogs/__НастройкиИнтеграции/Forms/ФормаСписка.xml similarity index 100% rename from src/Catalogs/__НастройкиИнтеграции/Forms/ФормаСписка.xml rename to src/cf/Catalogs/__НастройкиИнтеграции/Forms/ФормаСписка.xml diff --git a/src/Catalogs/__НастройкиИнтеграции/Forms/ФормаСписка/Ext/Form.xml b/src/cf/Catalogs/__НастройкиИнтеграции/Forms/ФормаСписка/Ext/Form.xml similarity index 100% rename from src/Catalogs/__НастройкиИнтеграции/Forms/ФормаСписка/Ext/Form.xml rename to src/cf/Catalogs/__НастройкиИнтеграции/Forms/ФормаСписка/Ext/Form.xml diff --git a/src/Catalogs/__НастройкиИнтеграции/Forms/ФормаСписка/Ext/Form/Module.bsl b/src/cf/Catalogs/__НастройкиИнтеграции/Forms/ФормаСписка/Ext/Form/Module.bsl similarity index 100% rename from src/Catalogs/__НастройкиИнтеграции/Forms/ФормаСписка/Ext/Form/Module.bsl rename to src/cf/Catalogs/__НастройкиИнтеграции/Forms/ФормаСписка/Ext/Form/Module.bsl diff --git a/src/Catalogs/__НастройкиИнтеграции/Forms/ФормаЭлемента.xml b/src/cf/Catalogs/__НастройкиИнтеграции/Forms/ФормаЭлемента.xml similarity index 100% rename from src/Catalogs/__НастройкиИнтеграции/Forms/ФормаЭлемента.xml rename to src/cf/Catalogs/__НастройкиИнтеграции/Forms/ФормаЭлемента.xml diff --git a/src/Catalogs/__НастройкиИнтеграции/Forms/ФормаЭлемента/Ext/Form.xml b/src/cf/Catalogs/__НастройкиИнтеграции/Forms/ФормаЭлемента/Ext/Form.xml similarity index 100% rename from src/Catalogs/__НастройкиИнтеграции/Forms/ФормаЭлемента/Ext/Form.xml rename to src/cf/Catalogs/__НастройкиИнтеграции/Forms/ФормаЭлемента/Ext/Form.xml diff --git a/src/Catalogs/__НастройкиИнтеграции/Forms/ФормаЭлемента/Ext/Form/Module.bsl b/src/cf/Catalogs/__НастройкиИнтеграции/Forms/ФормаЭлемента/Ext/Form/Module.bsl similarity index 100% rename from src/Catalogs/__НастройкиИнтеграции/Forms/ФормаЭлемента/Ext/Form/Module.bsl rename to src/cf/Catalogs/__НастройкиИнтеграции/Forms/ФормаЭлемента/Ext/Form/Module.bsl diff --git a/src/Catalogs/__НастройкиОтбораОбъектов.xml b/src/cf/Catalogs/__НастройкиОтбораОбъектов.xml similarity index 100% rename from src/Catalogs/__НастройкиОтбораОбъектов.xml rename to src/cf/Catalogs/__НастройкиОтбораОбъектов.xml diff --git a/src/Catalogs/__НастройкиОтбораОбъектов/Ext/ManagerModule.bsl b/src/cf/Catalogs/__НастройкиОтбораОбъектов/Ext/ManagerModule.bsl similarity index 100% rename from src/Catalogs/__НастройкиОтбораОбъектов/Ext/ManagerModule.bsl rename to src/cf/Catalogs/__НастройкиОтбораОбъектов/Ext/ManagerModule.bsl diff --git a/src/Catalogs/__НастройкиОтбораОбъектов/Forms/ФормаВыбораОбъектаМетаданных.xml b/src/cf/Catalogs/__НастройкиОтбораОбъектов/Forms/ФормаВыбораОбъектаМетаданных.xml similarity index 100% rename from src/Catalogs/__НастройкиОтбораОбъектов/Forms/ФормаВыбораОбъектаМетаданных.xml rename to src/cf/Catalogs/__НастройкиОтбораОбъектов/Forms/ФормаВыбораОбъектаМетаданных.xml diff --git a/src/Catalogs/__НастройкиОтбораОбъектов/Forms/ФормаВыбораОбъектаМетаданных/Ext/Form.xml b/src/cf/Catalogs/__НастройкиОтбораОбъектов/Forms/ФормаВыбораОбъектаМетаданных/Ext/Form.xml similarity index 100% rename from src/Catalogs/__НастройкиОтбораОбъектов/Forms/ФормаВыбораОбъектаМетаданных/Ext/Form.xml rename to src/cf/Catalogs/__НастройкиОтбораОбъектов/Forms/ФормаВыбораОбъектаМетаданных/Ext/Form.xml diff --git a/src/Catalogs/__НастройкиОтбораОбъектов/Forms/ФормаВыбораОбъектаМетаданных/Ext/Form/Items/Дерево/RowsPicture.bmp b/src/cf/Catalogs/__НастройкиОтбораОбъектов/Forms/ФормаВыбораОбъектаМетаданных/Ext/Form/Items/Дерево/RowsPicture.bmp similarity index 100% rename from src/Catalogs/__НастройкиОтбораОбъектов/Forms/ФормаВыбораОбъектаМетаданных/Ext/Form/Items/Дерево/RowsPicture.bmp rename to src/cf/Catalogs/__НастройкиОтбораОбъектов/Forms/ФормаВыбораОбъектаМетаданных/Ext/Form/Items/Дерево/RowsPicture.bmp diff --git a/src/Catalogs/__НастройкиОтбораОбъектов/Forms/ФормаВыбораОбъектаМетаданных/Ext/Form/Module.bsl b/src/cf/Catalogs/__НастройкиОтбораОбъектов/Forms/ФормаВыбораОбъектаМетаданных/Ext/Form/Module.bsl similarity index 100% rename from src/Catalogs/__НастройкиОтбораОбъектов/Forms/ФормаВыбораОбъектаМетаданных/Ext/Form/Module.bsl rename to src/cf/Catalogs/__НастройкиОтбораОбъектов/Forms/ФормаВыбораОбъектаМетаданных/Ext/Form/Module.bsl diff --git a/src/Catalogs/__НастройкиОтбораОбъектов/Forms/ФормаЭлемента.xml b/src/cf/Catalogs/__НастройкиОтбораОбъектов/Forms/ФормаЭлемента.xml similarity index 100% rename from src/Catalogs/__НастройкиОтбораОбъектов/Forms/ФормаЭлемента.xml rename to src/cf/Catalogs/__НастройкиОтбораОбъектов/Forms/ФормаЭлемента.xml diff --git a/src/Catalogs/__НастройкиОтбораОбъектов/Forms/ФормаЭлемента/Ext/Form.xml b/src/cf/Catalogs/__НастройкиОтбораОбъектов/Forms/ФормаЭлемента/Ext/Form.xml similarity index 100% rename from src/Catalogs/__НастройкиОтбораОбъектов/Forms/ФормаЭлемента/Ext/Form.xml rename to src/cf/Catalogs/__НастройкиОтбораОбъектов/Forms/ФормаЭлемента/Ext/Form.xml diff --git a/src/Catalogs/__НастройкиОтбораОбъектов/Forms/ФормаЭлемента/Ext/Form/Module.bsl b/src/cf/Catalogs/__НастройкиОтбораОбъектов/Forms/ФормаЭлемента/Ext/Form/Module.bsl similarity index 100% rename from src/Catalogs/__НастройкиОтбораОбъектов/Forms/ФормаЭлемента/Ext/Form/Module.bsl rename to src/cf/Catalogs/__НастройкиОтбораОбъектов/Forms/ФормаЭлемента/Ext/Form/Module.bsl diff --git a/src/Catalogs/__ПользовательскиеФункции.xml b/src/cf/Catalogs/__ПользовательскиеФункции.xml similarity index 100% rename from src/Catalogs/__ПользовательскиеФункции.xml rename to src/cf/Catalogs/__ПользовательскиеФункции.xml diff --git a/src/Catalogs/__ПользовательскиеФункции/Ext/Help.xml b/src/cf/Catalogs/__ПользовательскиеФункции/Ext/Help.xml similarity index 100% rename from src/Catalogs/__ПользовательскиеФункции/Ext/Help.xml rename to src/cf/Catalogs/__ПользовательскиеФункции/Ext/Help.xml diff --git a/src/Catalogs/__ПользовательскиеФункции/Ext/Help/ru.html b/src/cf/Catalogs/__ПользовательскиеФункции/Ext/Help/ru.html similarity index 100% rename from src/Catalogs/__ПользовательскиеФункции/Ext/Help/ru.html rename to src/cf/Catalogs/__ПользовательскиеФункции/Ext/Help/ru.html diff --git a/src/Catalogs/__ПользовательскиеФункции/Ext/ManagerModule.bsl b/src/cf/Catalogs/__ПользовательскиеФункции/Ext/ManagerModule.bsl similarity index 100% rename from src/Catalogs/__ПользовательскиеФункции/Ext/ManagerModule.bsl rename to src/cf/Catalogs/__ПользовательскиеФункции/Ext/ManagerModule.bsl diff --git a/src/Catalogs/__ПользовательскиеФункции/Ext/ObjectModule.bsl b/src/cf/Catalogs/__ПользовательскиеФункции/Ext/ObjectModule.bsl similarity index 100% rename from src/Catalogs/__ПользовательскиеФункции/Ext/ObjectModule.bsl rename to src/cf/Catalogs/__ПользовательскиеФункции/Ext/ObjectModule.bsl diff --git a/src/Catalogs/__ПользовательскиеФункции/Forms/УсловныйОператор.xml b/src/cf/Catalogs/__ПользовательскиеФункции/Forms/УсловныйОператор.xml similarity index 100% rename from src/Catalogs/__ПользовательскиеФункции/Forms/УсловныйОператор.xml rename to src/cf/Catalogs/__ПользовательскиеФункции/Forms/УсловныйОператор.xml diff --git a/src/Catalogs/__ПользовательскиеФункции/Forms/УсловныйОператор/Ext/Form.xml b/src/cf/Catalogs/__ПользовательскиеФункции/Forms/УсловныйОператор/Ext/Form.xml similarity index 100% rename from src/Catalogs/__ПользовательскиеФункции/Forms/УсловныйОператор/Ext/Form.xml rename to src/cf/Catalogs/__ПользовательскиеФункции/Forms/УсловныйОператор/Ext/Form.xml diff --git a/src/Catalogs/__ПользовательскиеФункции/Forms/УсловныйОператор/Ext/Form/Module.bsl b/src/cf/Catalogs/__ПользовательскиеФункции/Forms/УсловныйОператор/Ext/Form/Module.bsl similarity index 100% rename from src/Catalogs/__ПользовательскиеФункции/Forms/УсловныйОператор/Ext/Form/Module.bsl rename to src/cf/Catalogs/__ПользовательскиеФункции/Forms/УсловныйОператор/Ext/Form/Module.bsl diff --git a/src/Catalogs/__ПользовательскиеФункции/Forms/ФормаВыбора.xml b/src/cf/Catalogs/__ПользовательскиеФункции/Forms/ФормаВыбора.xml similarity index 100% rename from src/Catalogs/__ПользовательскиеФункции/Forms/ФормаВыбора.xml rename to src/cf/Catalogs/__ПользовательскиеФункции/Forms/ФормаВыбора.xml diff --git a/src/Catalogs/__ПользовательскиеФункции/Forms/ФормаВыбора/Ext/Form.xml b/src/cf/Catalogs/__ПользовательскиеФункции/Forms/ФормаВыбора/Ext/Form.xml similarity index 100% rename from src/Catalogs/__ПользовательскиеФункции/Forms/ФормаВыбора/Ext/Form.xml rename to src/cf/Catalogs/__ПользовательскиеФункции/Forms/ФормаВыбора/Ext/Form.xml diff --git a/src/Catalogs/__ПользовательскиеФункции/Forms/ФормаВыбора/Ext/Form/Module.bsl b/src/cf/Catalogs/__ПользовательскиеФункции/Forms/ФормаВыбора/Ext/Form/Module.bsl similarity index 100% rename from src/Catalogs/__ПользовательскиеФункции/Forms/ФормаВыбора/Ext/Form/Module.bsl rename to src/cf/Catalogs/__ПользовательскиеФункции/Forms/ФормаВыбора/Ext/Form/Module.bsl diff --git a/src/Catalogs/__ПользовательскиеФункции/Forms/ФормаГруппы.xml b/src/cf/Catalogs/__ПользовательскиеФункции/Forms/ФормаГруппы.xml similarity index 100% rename from src/Catalogs/__ПользовательскиеФункции/Forms/ФормаГруппы.xml rename to src/cf/Catalogs/__ПользовательскиеФункции/Forms/ФормаГруппы.xml diff --git a/src/Catalogs/__ПользовательскиеФункции/Forms/ФормаГруппы/Ext/Form.xml b/src/cf/Catalogs/__ПользовательскиеФункции/Forms/ФормаГруппы/Ext/Form.xml similarity index 100% rename from src/Catalogs/__ПользовательскиеФункции/Forms/ФормаГруппы/Ext/Form.xml rename to src/cf/Catalogs/__ПользовательскиеФункции/Forms/ФормаГруппы/Ext/Form.xml diff --git a/src/Catalogs/__ПользовательскиеФункции/Forms/ФормаГруппы/Ext/Form/Module.bsl b/src/cf/Catalogs/__ПользовательскиеФункции/Forms/ФормаГруппы/Ext/Form/Module.bsl similarity index 100% rename from src/Catalogs/__ПользовательскиеФункции/Forms/ФормаГруппы/Ext/Form/Module.bsl rename to src/cf/Catalogs/__ПользовательскиеФункции/Forms/ФормаГруппы/Ext/Form/Module.bsl diff --git a/src/Catalogs/__ПользовательскиеФункции/Forms/ФормаМассива.xml b/src/cf/Catalogs/__ПользовательскиеФункции/Forms/ФормаМассива.xml similarity index 100% rename from src/Catalogs/__ПользовательскиеФункции/Forms/ФормаМассива.xml rename to src/cf/Catalogs/__ПользовательскиеФункции/Forms/ФормаМассива.xml diff --git a/src/Catalogs/__ПользовательскиеФункции/Forms/ФормаМассива/Ext/Form.xml b/src/cf/Catalogs/__ПользовательскиеФункции/Forms/ФормаМассива/Ext/Form.xml similarity index 100% rename from src/Catalogs/__ПользовательскиеФункции/Forms/ФормаМассива/Ext/Form.xml rename to src/cf/Catalogs/__ПользовательскиеФункции/Forms/ФормаМассива/Ext/Form.xml diff --git a/src/Catalogs/__ПользовательскиеФункции/Forms/ФормаМассива/Ext/Form/Module.bsl b/src/cf/Catalogs/__ПользовательскиеФункции/Forms/ФормаМассива/Ext/Form/Module.bsl similarity index 100% rename from src/Catalogs/__ПользовательскиеФункции/Forms/ФормаМассива/Ext/Form/Module.bsl rename to src/cf/Catalogs/__ПользовательскиеФункции/Forms/ФормаМассива/Ext/Form/Module.bsl diff --git a/src/Catalogs/__ПользовательскиеФункции/Forms/ФормаСписка.xml b/src/cf/Catalogs/__ПользовательскиеФункции/Forms/ФормаСписка.xml similarity index 100% rename from src/Catalogs/__ПользовательскиеФункции/Forms/ФормаСписка.xml rename to src/cf/Catalogs/__ПользовательскиеФункции/Forms/ФормаСписка.xml diff --git a/src/Catalogs/__ПользовательскиеФункции/Forms/ФормаСписка/Ext/Form.xml b/src/cf/Catalogs/__ПользовательскиеФункции/Forms/ФормаСписка/Ext/Form.xml similarity index 100% rename from src/Catalogs/__ПользовательскиеФункции/Forms/ФормаСписка/Ext/Form.xml rename to src/cf/Catalogs/__ПользовательскиеФункции/Forms/ФормаСписка/Ext/Form.xml diff --git a/src/Catalogs/__ПользовательскиеФункции/Forms/ФормаСписка/Ext/Form/Module.bsl b/src/cf/Catalogs/__ПользовательскиеФункции/Forms/ФормаСписка/Ext/Form/Module.bsl similarity index 100% rename from src/Catalogs/__ПользовательскиеФункции/Forms/ФормаСписка/Ext/Form/Module.bsl rename to src/cf/Catalogs/__ПользовательскиеФункции/Forms/ФормаСписка/Ext/Form/Module.bsl diff --git a/src/Catalogs/__ПользовательскиеФункции/Forms/ФормаСтруктуры.xml b/src/cf/Catalogs/__ПользовательскиеФункции/Forms/ФормаСтруктуры.xml similarity index 100% rename from src/Catalogs/__ПользовательскиеФункции/Forms/ФормаСтруктуры.xml rename to src/cf/Catalogs/__ПользовательскиеФункции/Forms/ФормаСтруктуры.xml diff --git a/src/Catalogs/__ПользовательскиеФункции/Forms/ФормаСтруктуры/Ext/Form.xml b/src/cf/Catalogs/__ПользовательскиеФункции/Forms/ФормаСтруктуры/Ext/Form.xml similarity index 100% rename from src/Catalogs/__ПользовательскиеФункции/Forms/ФормаСтруктуры/Ext/Form.xml rename to src/cf/Catalogs/__ПользовательскиеФункции/Forms/ФормаСтруктуры/Ext/Form.xml diff --git a/src/Catalogs/__ПользовательскиеФункции/Forms/ФормаСтруктуры/Ext/Form/Module.bsl b/src/cf/Catalogs/__ПользовательскиеФункции/Forms/ФормаСтруктуры/Ext/Form/Module.bsl similarity index 100% rename from src/Catalogs/__ПользовательскиеФункции/Forms/ФормаСтруктуры/Ext/Form/Module.bsl rename to src/cf/Catalogs/__ПользовательскиеФункции/Forms/ФормаСтруктуры/Ext/Form/Module.bsl diff --git a/src/Catalogs/__ПользовательскиеФункции/Forms/ФормаТаблицыЗначений.xml b/src/cf/Catalogs/__ПользовательскиеФункции/Forms/ФормаТаблицыЗначений.xml similarity index 100% rename from src/Catalogs/__ПользовательскиеФункции/Forms/ФормаТаблицыЗначений.xml rename to src/cf/Catalogs/__ПользовательскиеФункции/Forms/ФормаТаблицыЗначений.xml diff --git a/src/Catalogs/__ПользовательскиеФункции/Forms/ФормаТаблицыЗначений/Ext/Form.xml b/src/cf/Catalogs/__ПользовательскиеФункции/Forms/ФормаТаблицыЗначений/Ext/Form.xml similarity index 100% rename from src/Catalogs/__ПользовательскиеФункции/Forms/ФормаТаблицыЗначений/Ext/Form.xml rename to src/cf/Catalogs/__ПользовательскиеФункции/Forms/ФормаТаблицыЗначений/Ext/Form.xml diff --git a/src/Catalogs/__ПользовательскиеФункции/Forms/ФормаТаблицыЗначений/Ext/Form/Module.bsl b/src/cf/Catalogs/__ПользовательскиеФункции/Forms/ФормаТаблицыЗначений/Ext/Form/Module.bsl similarity index 100% rename from src/Catalogs/__ПользовательскиеФункции/Forms/ФормаТаблицыЗначений/Ext/Form/Module.bsl rename to src/cf/Catalogs/__ПользовательскиеФункции/Forms/ФормаТаблицыЗначений/Ext/Form/Module.bsl diff --git a/src/Catalogs/__ПользовательскиеФункции/Forms/ФормаЭлемента.xml b/src/cf/Catalogs/__ПользовательскиеФункции/Forms/ФормаЭлемента.xml similarity index 100% rename from src/Catalogs/__ПользовательскиеФункции/Forms/ФормаЭлемента.xml rename to src/cf/Catalogs/__ПользовательскиеФункции/Forms/ФормаЭлемента.xml diff --git a/src/Catalogs/__ПользовательскиеФункции/Forms/ФормаЭлемента/Ext/Form.xml b/src/cf/Catalogs/__ПользовательскиеФункции/Forms/ФормаЭлемента/Ext/Form.xml similarity index 100% rename from src/Catalogs/__ПользовательскиеФункции/Forms/ФормаЭлемента/Ext/Form.xml rename to src/cf/Catalogs/__ПользовательскиеФункции/Forms/ФормаЭлемента/Ext/Form.xml diff --git a/src/Catalogs/__ПользовательскиеФункции/Forms/ФормаЭлемента/Ext/Form/Module.bsl b/src/cf/Catalogs/__ПользовательскиеФункции/Forms/ФормаЭлемента/Ext/Form/Module.bsl similarity index 100% rename from src/Catalogs/__ПользовательскиеФункции/Forms/ФормаЭлемента/Ext/Form/Module.bsl rename to src/cf/Catalogs/__ПользовательскиеФункции/Forms/ФормаЭлемента/Ext/Form/Module.bsl diff --git a/src/Catalogs/__ПользовательскиеФункции/Templates/НастройкиПоУмолчанию.xml b/src/cf/Catalogs/__ПользовательскиеФункции/Templates/НастройкиПоУмолчанию.xml similarity index 100% rename from src/Catalogs/__ПользовательскиеФункции/Templates/НастройкиПоУмолчанию.xml rename to src/cf/Catalogs/__ПользовательскиеФункции/Templates/НастройкиПоУмолчанию.xml diff --git a/src/Catalogs/__ПользовательскиеФункции/Templates/НастройкиПоУмолчанию/Ext/Template.txt b/src/cf/Catalogs/__ПользовательскиеФункции/Templates/НастройкиПоУмолчанию/Ext/Template.txt similarity index 100% rename from src/Catalogs/__ПользовательскиеФункции/Templates/НастройкиПоУмолчанию/Ext/Template.txt rename to src/cf/Catalogs/__ПользовательскиеФункции/Templates/НастройкиПоУмолчанию/Ext/Template.txt diff --git a/src/Catalogs/__ТипСоответствияОбъектовИБ.xml b/src/cf/Catalogs/__ТипСоответствияОбъектовИБ.xml similarity index 100% rename from src/Catalogs/__ТипСоответствияОбъектовИБ.xml rename to src/cf/Catalogs/__ТипСоответствияОбъектовИБ.xml diff --git a/src/Catalogs/__ТипСоответствияОбъектовИБ/Ext/ManagerModule.bsl b/src/cf/Catalogs/__ТипСоответствияОбъектовИБ/Ext/ManagerModule.bsl similarity index 100% rename from src/Catalogs/__ТипСоответствияОбъектовИБ/Ext/ManagerModule.bsl rename to src/cf/Catalogs/__ТипСоответствияОбъектовИБ/Ext/ManagerModule.bsl diff --git a/src/Catalogs/__ТипСоответствияОбъектовИБ/Forms/ФормаСписка.xml b/src/cf/Catalogs/__ТипСоответствияОбъектовИБ/Forms/ФормаСписка.xml similarity index 100% rename from src/Catalogs/__ТипСоответствияОбъектовИБ/Forms/ФормаСписка.xml rename to src/cf/Catalogs/__ТипСоответствияОбъектовИБ/Forms/ФормаСписка.xml diff --git a/src/Catalogs/__ТипСоответствияОбъектовИБ/Forms/ФормаСписка/Ext/Form.xml b/src/cf/Catalogs/__ТипСоответствияОбъектовИБ/Forms/ФормаСписка/Ext/Form.xml similarity index 100% rename from src/Catalogs/__ТипСоответствияОбъектовИБ/Forms/ФормаСписка/Ext/Form.xml rename to src/cf/Catalogs/__ТипСоответствияОбъектовИБ/Forms/ФормаСписка/Ext/Form.xml diff --git a/src/Catalogs/__ТипСоответствияОбъектовИБ/Forms/ФормаСписка/Ext/Form/Module.bsl b/src/cf/Catalogs/__ТипСоответствияОбъектовИБ/Forms/ФормаСписка/Ext/Form/Module.bsl similarity index 100% rename from src/Catalogs/__ТипСоответствияОбъектовИБ/Forms/ФормаСписка/Ext/Form/Module.bsl rename to src/cf/Catalogs/__ТипСоответствияОбъектовИБ/Forms/ФормаСписка/Ext/Form/Module.bsl diff --git a/src/ChartsOfCharacteristicTypes/__ПредопределенныеЗначения.xml b/src/cf/ChartsOfCharacteristicTypes/__ПредопределенныеЗначения.xml similarity index 100% rename from src/ChartsOfCharacteristicTypes/__ПредопределенныеЗначения.xml rename to src/cf/ChartsOfCharacteristicTypes/__ПредопределенныеЗначения.xml diff --git a/src/ChartsOfCharacteristicTypes/__ПредопределенныеЗначения/Ext/ManagerModule.bsl b/src/cf/ChartsOfCharacteristicTypes/__ПредопределенныеЗначения/Ext/ManagerModule.bsl similarity index 100% rename from src/ChartsOfCharacteristicTypes/__ПредопределенныеЗначения/Ext/ManagerModule.bsl rename to src/cf/ChartsOfCharacteristicTypes/__ПредопределенныеЗначения/Ext/ManagerModule.bsl diff --git a/src/ChartsOfCharacteristicTypes/__ПредопределенныеЗначения/Ext/ObjectModule.bsl b/src/cf/ChartsOfCharacteristicTypes/__ПредопределенныеЗначения/Ext/ObjectModule.bsl similarity index 100% rename from src/ChartsOfCharacteristicTypes/__ПредопределенныеЗначения/Ext/ObjectModule.bsl rename to src/cf/ChartsOfCharacteristicTypes/__ПредопределенныеЗначения/Ext/ObjectModule.bsl diff --git a/src/ChartsOfCharacteristicTypes/__ПредопределенныеЗначения/Forms/ФормаГруппы.xml b/src/cf/ChartsOfCharacteristicTypes/__ПредопределенныеЗначения/Forms/ФормаГруппы.xml similarity index 100% rename from src/ChartsOfCharacteristicTypes/__ПредопределенныеЗначения/Forms/ФормаГруппы.xml rename to src/cf/ChartsOfCharacteristicTypes/__ПредопределенныеЗначения/Forms/ФормаГруппы.xml diff --git a/src/ChartsOfCharacteristicTypes/__ПредопределенныеЗначения/Forms/ФормаГруппы/Ext/Form.xml b/src/cf/ChartsOfCharacteristicTypes/__ПредопределенныеЗначения/Forms/ФормаГруппы/Ext/Form.xml similarity index 100% rename from src/ChartsOfCharacteristicTypes/__ПредопределенныеЗначения/Forms/ФормаГруппы/Ext/Form.xml rename to src/cf/ChartsOfCharacteristicTypes/__ПредопределенныеЗначения/Forms/ФормаГруппы/Ext/Form.xml diff --git a/src/ChartsOfCharacteristicTypes/__ПредопределенныеЗначения/Forms/ФормаГруппы/Ext/Form/Module.bsl b/src/cf/ChartsOfCharacteristicTypes/__ПредопределенныеЗначения/Forms/ФормаГруппы/Ext/Form/Module.bsl similarity index 100% rename from src/ChartsOfCharacteristicTypes/__ПредопределенныеЗначения/Forms/ФормаГруппы/Ext/Form/Module.bsl rename to src/cf/ChartsOfCharacteristicTypes/__ПредопределенныеЗначения/Forms/ФормаГруппы/Ext/Form/Module.bsl diff --git a/src/ChartsOfCharacteristicTypes/__ПредопределенныеЗначения/Forms/ФормаСписка.xml b/src/cf/ChartsOfCharacteristicTypes/__ПредопределенныеЗначения/Forms/ФормаСписка.xml similarity index 100% rename from src/ChartsOfCharacteristicTypes/__ПредопределенныеЗначения/Forms/ФормаСписка.xml rename to src/cf/ChartsOfCharacteristicTypes/__ПредопределенныеЗначения/Forms/ФормаСписка.xml diff --git a/src/ChartsOfCharacteristicTypes/__ПредопределенныеЗначения/Forms/ФормаСписка/Ext/Form.xml b/src/cf/ChartsOfCharacteristicTypes/__ПредопределенныеЗначения/Forms/ФормаСписка/Ext/Form.xml similarity index 100% rename from src/ChartsOfCharacteristicTypes/__ПредопределенныеЗначения/Forms/ФормаСписка/Ext/Form.xml rename to src/cf/ChartsOfCharacteristicTypes/__ПредопределенныеЗначения/Forms/ФормаСписка/Ext/Form.xml diff --git a/src/ChartsOfCharacteristicTypes/__ПредопределенныеЗначения/Forms/ФормаСписка/Ext/Form/Module.bsl b/src/cf/ChartsOfCharacteristicTypes/__ПредопределенныеЗначения/Forms/ФормаСписка/Ext/Form/Module.bsl similarity index 100% rename from src/ChartsOfCharacteristicTypes/__ПредопределенныеЗначения/Forms/ФормаСписка/Ext/Form/Module.bsl rename to src/cf/ChartsOfCharacteristicTypes/__ПредопределенныеЗначения/Forms/ФормаСписка/Ext/Form/Module.bsl diff --git a/src/ChartsOfCharacteristicTypes/__ПредопределенныеЗначения/Forms/ФормаЭлемента.xml b/src/cf/ChartsOfCharacteristicTypes/__ПредопределенныеЗначения/Forms/ФормаЭлемента.xml similarity index 100% rename from src/ChartsOfCharacteristicTypes/__ПредопределенныеЗначения/Forms/ФормаЭлемента.xml rename to src/cf/ChartsOfCharacteristicTypes/__ПредопределенныеЗначения/Forms/ФормаЭлемента.xml diff --git a/src/ChartsOfCharacteristicTypes/__ПредопределенныеЗначения/Forms/ФормаЭлемента/Ext/Form.xml b/src/cf/ChartsOfCharacteristicTypes/__ПредопределенныеЗначения/Forms/ФормаЭлемента/Ext/Form.xml similarity index 100% rename from src/ChartsOfCharacteristicTypes/__ПредопределенныеЗначения/Forms/ФормаЭлемента/Ext/Form.xml rename to src/cf/ChartsOfCharacteristicTypes/__ПредопределенныеЗначения/Forms/ФормаЭлемента/Ext/Form.xml diff --git a/src/ChartsOfCharacteristicTypes/__ПредопределенныеЗначения/Forms/ФормаЭлемента/Ext/Form/Module.bsl b/src/cf/ChartsOfCharacteristicTypes/__ПредопределенныеЗначения/Forms/ФормаЭлемента/Ext/Form/Module.bsl similarity index 100% rename from src/ChartsOfCharacteristicTypes/__ПредопределенныеЗначения/Forms/ФормаЭлемента/Ext/Form/Module.bsl rename to src/cf/ChartsOfCharacteristicTypes/__ПредопределенныеЗначения/Forms/ФормаЭлемента/Ext/Form/Module.bsl diff --git a/src/CommonForms/__ФормаВыбораПоля.xml b/src/cf/CommonForms/__ФормаВыбораПоля.xml similarity index 100% rename from src/CommonForms/__ФормаВыбораПоля.xml rename to src/cf/CommonForms/__ФормаВыбораПоля.xml diff --git a/src/CommonForms/__ФормаВыбораПоля/Ext/Form.xml b/src/cf/CommonForms/__ФормаВыбораПоля/Ext/Form.xml similarity index 100% rename from src/CommonForms/__ФормаВыбораПоля/Ext/Form.xml rename to src/cf/CommonForms/__ФормаВыбораПоля/Ext/Form.xml diff --git a/src/CommonForms/__ФормаВыбораПоля/Ext/Form/Module.bsl b/src/cf/CommonForms/__ФормаВыбораПоля/Ext/Form/Module.bsl similarity index 100% rename from src/CommonForms/__ФормаВыбораПоля/Ext/Form/Module.bsl rename to src/cf/CommonForms/__ФормаВыбораПоля/Ext/Form/Module.bsl diff --git a/src/CommonForms/__ФормаВыбораПоля/Ext/Help.xml b/src/cf/CommonForms/__ФормаВыбораПоля/Ext/Help.xml similarity index 100% rename from src/CommonForms/__ФормаВыбораПоля/Ext/Help.xml rename to src/cf/CommonForms/__ФормаВыбораПоля/Ext/Help.xml diff --git a/src/CommonForms/__ФормаВыбораПоля/Ext/Help/ru.html b/src/cf/CommonForms/__ФормаВыбораПоля/Ext/Help/ru.html similarity index 100% rename from src/CommonForms/__ФормаВыбораПоля/Ext/Help/ru.html rename to src/cf/CommonForms/__ФормаВыбораПоля/Ext/Help/ru.html diff --git a/src/CommonModules/__ДокументыОбработкаЗаполнения.xml b/src/cf/CommonModules/__ДокументыОбработкаЗаполнения.xml similarity index 100% rename from src/CommonModules/__ДокументыОбработкаЗаполнения.xml rename to src/cf/CommonModules/__ДокументыОбработкаЗаполнения.xml diff --git a/src/CommonModules/__ДокументыОбработкаЗаполнения/Ext/Module.bsl b/src/cf/CommonModules/__ДокументыОбработкаЗаполнения/Ext/Module.bsl similarity index 100% rename from src/CommonModules/__ДокументыОбработкаЗаполнения/Ext/Module.bsl rename to src/cf/CommonModules/__ДокументыОбработкаЗаполнения/Ext/Module.bsl diff --git a/src/CommonModules/__ДокументыОбработкаПроведения.xml b/src/cf/CommonModules/__ДокументыОбработкаПроведения.xml similarity index 100% rename from src/CommonModules/__ДокументыОбработкаПроведения.xml rename to src/cf/CommonModules/__ДокументыОбработкаПроведения.xml diff --git a/src/CommonModules/__ДокументыОбработкаПроведения/Ext/Module.bsl b/src/cf/CommonModules/__ДокументыОбработкаПроведения/Ext/Module.bsl similarity index 100% rename from src/CommonModules/__ДокументыОбработкаПроведения/Ext/Module.bsl rename to src/cf/CommonModules/__ДокументыОбработкаПроведения/Ext/Module.bsl diff --git a/src/CommonModules/__ДокументыПередЗаписью.xml b/src/cf/CommonModules/__ДокументыПередЗаписью.xml similarity index 100% rename from src/CommonModules/__ДокументыПередЗаписью.xml rename to src/cf/CommonModules/__ДокументыПередЗаписью.xml diff --git a/src/CommonModules/__ДокументыПередЗаписью/Ext/Module.bsl b/src/cf/CommonModules/__ДокументыПередЗаписью/Ext/Module.bsl similarity index 100% rename from src/CommonModules/__ДокументыПередЗаписью/Ext/Module.bsl rename to src/cf/CommonModules/__ДокументыПередЗаписью/Ext/Module.bsl diff --git a/src/CommonModules/__ДокументыПриЗаписи.xml b/src/cf/CommonModules/__ДокументыПриЗаписи.xml similarity index 100% rename from src/CommonModules/__ДокументыПриЗаписи.xml rename to src/cf/CommonModules/__ДокументыПриЗаписи.xml diff --git a/src/CommonModules/__ДокументыПриЗаписи/Ext/Module.bsl b/src/cf/CommonModules/__ДокументыПриЗаписи/Ext/Module.bsl similarity index 100% rename from src/CommonModules/__ДокументыПриЗаписи/Ext/Module.bsl rename to src/cf/CommonModules/__ДокументыПриЗаписи/Ext/Module.bsl diff --git a/src/CommonModules/__ДокументыПриКопировании.xml b/src/cf/CommonModules/__ДокументыПриКопировании.xml similarity index 100% rename from src/CommonModules/__ДокументыПриКопировании.xml rename to src/cf/CommonModules/__ДокументыПриКопировании.xml diff --git a/src/CommonModules/__ДокументыПриКопировании/Ext/Module.bsl b/src/cf/CommonModules/__ДокументыПриКопировании/Ext/Module.bsl similarity index 100% rename from src/CommonModules/__ДокументыПриКопировании/Ext/Module.bsl rename to src/cf/CommonModules/__ДокументыПриКопировании/Ext/Module.bsl diff --git a/src/CommonModules/__ЖурналРегистрации.xml b/src/cf/CommonModules/__ЖурналРегистрации.xml similarity index 100% rename from src/CommonModules/__ЖурналРегистрации.xml rename to src/cf/CommonModules/__ЖурналРегистрации.xml diff --git a/src/CommonModules/__ЖурналРегистрации/Ext/Module.bsl b/src/cf/CommonModules/__ЖурналРегистрации/Ext/Module.bsl similarity index 100% rename from src/CommonModules/__ЖурналРегистрации/Ext/Module.bsl rename to src/cf/CommonModules/__ЖурналРегистрации/Ext/Module.bsl diff --git a/src/CommonModules/__ЖурналРегистрацииСлужебный.xml b/src/cf/CommonModules/__ЖурналРегистрацииСлужебный.xml similarity index 100% rename from src/CommonModules/__ЖурналРегистрацииСлужебный.xml rename to src/cf/CommonModules/__ЖурналРегистрацииСлужебный.xml diff --git a/src/CommonModules/__ЖурналРегистрацииСлужебный/Ext/Module.bsl b/src/cf/CommonModules/__ЖурналРегистрацииСлужебный/Ext/Module.bsl similarity index 100% rename from src/CommonModules/__ЖурналРегистрацииСлужебный/Ext/Module.bsl rename to src/cf/CommonModules/__ЖурналРегистрацииСлужебный/Ext/Module.bsl diff --git a/src/CommonModules/__ЗагрузкаФайлаЧерезТабличныйДокументВызовСервера.xml b/src/cf/CommonModules/__ЗагрузкаФайлаЧерезТабличныйДокументВызовСервера.xml similarity index 100% rename from src/CommonModules/__ЗагрузкаФайлаЧерезТабличныйДокументВызовСервера.xml rename to src/cf/CommonModules/__ЗагрузкаФайлаЧерезТабличныйДокументВызовСервера.xml diff --git a/src/CommonModules/__ЗагрузкаФайлаЧерезТабличныйДокументВызовСервера/Ext/Module.bsl b/src/cf/CommonModules/__ЗагрузкаФайлаЧерезТабличныйДокументВызовСервера/Ext/Module.bsl similarity index 100% rename from src/CommonModules/__ЗагрузкаФайлаЧерезТабличныйДокументВызовСервера/Ext/Module.bsl rename to src/cf/CommonModules/__ЗагрузкаФайлаЧерезТабличныйДокументВызовСервера/Ext/Module.bsl diff --git a/src/CommonModules/__ЗагрузкаФайлаЧерезТабличныйДокументКлиент.xml b/src/cf/CommonModules/__ЗагрузкаФайлаЧерезТабличныйДокументКлиент.xml similarity index 100% rename from src/CommonModules/__ЗагрузкаФайлаЧерезТабличныйДокументКлиент.xml rename to src/cf/CommonModules/__ЗагрузкаФайлаЧерезТабличныйДокументКлиент.xml diff --git a/src/CommonModules/__ЗагрузкаФайлаЧерезТабличныйДокументКлиент/Ext/Module.bsl b/src/cf/CommonModules/__ЗагрузкаФайлаЧерезТабличныйДокументКлиент/Ext/Module.bsl similarity index 100% rename from src/CommonModules/__ЗагрузкаФайлаЧерезТабличныйДокументКлиент/Ext/Module.bsl rename to src/cf/CommonModules/__ЗагрузкаФайлаЧерезТабличныйДокументКлиент/Ext/Module.bsl diff --git a/src/CommonModules/__ИнтеграцииПереопределяемый.xml b/src/cf/CommonModules/__ИнтеграцииПереопределяемый.xml similarity index 100% rename from src/CommonModules/__ИнтеграцииПереопределяемый.xml rename to src/cf/CommonModules/__ИнтеграцииПереопределяемый.xml diff --git a/src/CommonModules/__ИнтеграцииПереопределяемый/Ext/Module.bsl b/src/cf/CommonModules/__ИнтеграцииПереопределяемый/Ext/Module.bsl similarity index 100% rename from src/CommonModules/__ИнтеграцииПереопределяемый/Ext/Module.bsl rename to src/cf/CommonModules/__ИнтеграцииПереопределяемый/Ext/Module.bsl diff --git a/src/CommonModules/__ИнтеграцииСервер.xml b/src/cf/CommonModules/__ИнтеграцииСервер.xml similarity index 100% rename from src/CommonModules/__ИнтеграцииСервер.xml rename to src/cf/CommonModules/__ИнтеграцииСервер.xml diff --git a/src/CommonModules/__ИнтеграцииСервер/Ext/Module.bsl b/src/cf/CommonModules/__ИнтеграцииСервер/Ext/Module.bsl similarity index 100% rename from src/CommonModules/__ИнтеграцииСервер/Ext/Module.bsl rename to src/cf/CommonModules/__ИнтеграцииСервер/Ext/Module.bsl diff --git a/src/CommonModules/__КоннекторHTTP.xml b/src/cf/CommonModules/__КоннекторHTTP.xml similarity index 100% rename from src/CommonModules/__КоннекторHTTP.xml rename to src/cf/CommonModules/__КоннекторHTTP.xml diff --git a/src/CommonModules/__КоннекторHTTP/Ext/Module.bsl b/src/cf/CommonModules/__КоннекторHTTP/Ext/Module.bsl similarity index 100% rename from src/CommonModules/__КоннекторHTTP/Ext/Module.bsl rename to src/cf/CommonModules/__КоннекторHTTP/Ext/Module.bsl diff --git a/src/CommonModules/__МетодыРегламентныхЗаданийСервер.xml b/src/cf/CommonModules/__МетодыРегламентныхЗаданийСервер.xml similarity index 100% rename from src/CommonModules/__МетодыРегламентныхЗаданийСервер.xml rename to src/cf/CommonModules/__МетодыРегламентныхЗаданийСервер.xml diff --git a/src/CommonModules/__МетодыРегламентныхЗаданийСервер/Ext/Module.bsl b/src/cf/CommonModules/__МетодыРегламентныхЗаданийСервер/Ext/Module.bsl similarity index 100% rename from src/CommonModules/__МетодыРегламентныхЗаданийСервер/Ext/Module.bsl rename to src/cf/CommonModules/__МетодыРегламентныхЗаданийСервер/Ext/Module.bsl diff --git a/src/CommonModules/__МодификацияКонфигурацииКлиентПереопределяемый.xml b/src/cf/CommonModules/__МодификацияКонфигурацииКлиентПереопределяемый.xml similarity index 100% rename from src/CommonModules/__МодификацияКонфигурацииКлиентПереопределяемый.xml rename to src/cf/CommonModules/__МодификацияКонфигурацииКлиентПереопределяемый.xml diff --git a/src/CommonModules/__МодификацияКонфигурацииКлиентПереопределяемый/Ext/Module.bsl b/src/cf/CommonModules/__МодификацияКонфигурацииКлиентПереопределяемый/Ext/Module.bsl similarity index 100% rename from src/CommonModules/__МодификацияКонфигурацииКлиентПереопределяемый/Ext/Module.bsl rename to src/cf/CommonModules/__МодификацияКонфигурацииКлиентПереопределяемый/Ext/Module.bsl diff --git a/src/CommonModules/__МодификацияКонфигурацииКлиентСерверПереопределяемый.xml b/src/cf/CommonModules/__МодификацияКонфигурацииКлиентСерверПереопределяемый.xml similarity index 100% rename from src/CommonModules/__МодификацияКонфигурацииКлиентСерверПереопределяемый.xml rename to src/cf/CommonModules/__МодификацияКонфигурацииКлиентСерверПереопределяемый.xml diff --git a/src/CommonModules/__МодификацияКонфигурацииКлиентСерверПереопределяемый/Ext/Module.bsl b/src/cf/CommonModules/__МодификацияКонфигурацииКлиентСерверПереопределяемый/Ext/Module.bsl similarity index 100% rename from src/CommonModules/__МодификацияКонфигурацииКлиентСерверПереопределяемый/Ext/Module.bsl rename to src/cf/CommonModules/__МодификацияКонфигурацииКлиентСерверПереопределяемый/Ext/Module.bsl diff --git a/src/CommonModules/__МодификацияКонфигурацииПереопределяемый.xml b/src/cf/CommonModules/__МодификацияКонфигурацииПереопределяемый.xml similarity index 100% rename from src/CommonModules/__МодификацияКонфигурацииПереопределяемый.xml rename to src/cf/CommonModules/__МодификацияКонфигурацииПереопределяемый.xml diff --git a/src/CommonModules/__МодификацияКонфигурацииПереопределяемый/Ext/Module.bsl b/src/cf/CommonModules/__МодификацияКонфигурацииПереопределяемый/Ext/Module.bsl similarity index 100% rename from src/CommonModules/__МодификацияКонфигурацииПереопределяемый/Ext/Module.bsl rename to src/cf/CommonModules/__МодификацияКонфигурацииПереопределяемый/Ext/Module.bsl diff --git a/src/CommonModules/__МодификацияКонфигурацииПереопределяемыйДокумент.xml b/src/cf/CommonModules/__МодификацияКонфигурацииПереопределяемыйДокумент.xml similarity index 100% rename from src/CommonModules/__МодификацияКонфигурацииПереопределяемыйДокумент.xml rename to src/cf/CommonModules/__МодификацияКонфигурацииПереопределяемыйДокумент.xml diff --git a/src/CommonModules/__МодификацияКонфигурацииПереопределяемыйДокумент/Ext/Module.bsl b/src/cf/CommonModules/__МодификацияКонфигурацииПереопределяемыйДокумент/Ext/Module.bsl similarity index 100% rename from src/CommonModules/__МодификацияКонфигурацииПереопределяемыйДокумент/Ext/Module.bsl rename to src/cf/CommonModules/__МодификацияКонфигурацииПереопределяемыйДокумент/Ext/Module.bsl diff --git a/src/CommonModules/__МодификацияКонфигурацииПереопределяемыйПланВидовХарактеристик.xml b/src/cf/CommonModules/__МодификацияКонфигурацииПереопределяемыйПланВидовХарактеристик.xml similarity index 100% rename from src/CommonModules/__МодификацияКонфигурацииПереопределяемыйПланВидовХарактеристик.xml rename to src/cf/CommonModules/__МодификацияКонфигурацииПереопределяемыйПланВидовХарактеристик.xml diff --git a/src/CommonModules/__МодификацияКонфигурацииПереопределяемыйПланВидовХарактеристик/Ext/Module.bsl b/src/cf/CommonModules/__МодификацияКонфигурацииПереопределяемыйПланВидовХарактеристик/Ext/Module.bsl similarity index 100% rename from src/CommonModules/__МодификацияКонфигурацииПереопределяемыйПланВидовХарактеристик/Ext/Module.bsl rename to src/cf/CommonModules/__МодификацияКонфигурацииПереопределяемыйПланВидовХарактеристик/Ext/Module.bsl diff --git a/src/CommonModules/__ОбновлениеИнформационнойБазыПБП.xml b/src/cf/CommonModules/__ОбновлениеИнформационнойБазыПБП.xml similarity index 100% rename from src/CommonModules/__ОбновлениеИнформационнойБазыПБП.xml rename to src/cf/CommonModules/__ОбновлениеИнформационнойБазыПБП.xml diff --git a/src/CommonModules/__ОбновлениеИнформационнойБазыПБП/Ext/Module.bsl b/src/cf/CommonModules/__ОбновлениеИнформационнойБазыПБП/Ext/Module.bsl similarity index 100% rename from src/CommonModules/__ОбновлениеИнформационнойБазыПБП/Ext/Module.bsl rename to src/cf/CommonModules/__ОбновлениеИнформационнойБазыПБП/Ext/Module.bsl diff --git a/src/CommonModules/__ОбщегоНазначенияВызовСервера.xml b/src/cf/CommonModules/__ОбщегоНазначенияВызовСервера.xml similarity index 100% rename from src/CommonModules/__ОбщегоНазначенияВызовСервера.xml rename to src/cf/CommonModules/__ОбщегоНазначенияВызовСервера.xml diff --git a/src/CommonModules/__ОбщегоНазначенияВызовСервера/Ext/Module.bsl b/src/cf/CommonModules/__ОбщегоНазначенияВызовСервера/Ext/Module.bsl similarity index 100% rename from src/CommonModules/__ОбщегоНазначенияВызовСервера/Ext/Module.bsl rename to src/cf/CommonModules/__ОбщегоНазначенияВызовСервера/Ext/Module.bsl diff --git a/src/CommonModules/__ОбщегоНазначенияКлиент.xml b/src/cf/CommonModules/__ОбщегоНазначенияКлиент.xml similarity index 100% rename from src/CommonModules/__ОбщегоНазначенияКлиент.xml rename to src/cf/CommonModules/__ОбщегоНазначенияКлиент.xml diff --git a/src/CommonModules/__ОбщегоНазначенияКлиент/Ext/Module.bsl b/src/cf/CommonModules/__ОбщегоНазначенияКлиент/Ext/Module.bsl similarity index 100% rename from src/CommonModules/__ОбщегоНазначенияКлиент/Ext/Module.bsl rename to src/cf/CommonModules/__ОбщегоНазначенияКлиент/Ext/Module.bsl diff --git a/src/CommonModules/__ОбщегоНазначенияКлиентСервер.xml b/src/cf/CommonModules/__ОбщегоНазначенияКлиентСервер.xml similarity index 100% rename from src/CommonModules/__ОбщегоНазначенияКлиентСервер.xml rename to src/cf/CommonModules/__ОбщегоНазначенияКлиентСервер.xml diff --git a/src/CommonModules/__ОбщегоНазначенияКлиентСервер/Ext/Module.bsl b/src/cf/CommonModules/__ОбщегоНазначенияКлиентСервер/Ext/Module.bsl similarity index 100% rename from src/CommonModules/__ОбщегоНазначенияКлиентСервер/Ext/Module.bsl rename to src/cf/CommonModules/__ОбщегоНазначенияКлиентСервер/Ext/Module.bsl diff --git a/src/CommonModules/__ОбщегоНазначенияПовтИсп.xml b/src/cf/CommonModules/__ОбщегоНазначенияПовтИсп.xml similarity index 100% rename from src/CommonModules/__ОбщегоНазначенияПовтИсп.xml rename to src/cf/CommonModules/__ОбщегоНазначенияПовтИсп.xml diff --git a/src/CommonModules/__ОбщегоНазначенияПовтИсп/Ext/Module.bsl b/src/cf/CommonModules/__ОбщегоНазначенияПовтИсп/Ext/Module.bsl similarity index 100% rename from src/CommonModules/__ОбщегоНазначенияПовтИсп/Ext/Module.bsl rename to src/cf/CommonModules/__ОбщегоНазначенияПовтИсп/Ext/Module.bsl diff --git a/src/CommonModules/__ОбщегоНазначенияПолныеПрава.xml b/src/cf/CommonModules/__ОбщегоНазначенияПолныеПрава.xml similarity index 100% rename from src/CommonModules/__ОбщегоНазначенияПолныеПрава.xml rename to src/cf/CommonModules/__ОбщегоНазначенияПолныеПрава.xml diff --git a/src/CommonModules/__ОбщегоНазначенияПолныеПрава/Ext/Module.bsl b/src/cf/CommonModules/__ОбщегоНазначенияПолныеПрава/Ext/Module.bsl similarity index 100% rename from src/CommonModules/__ОбщегоНазначенияПолныеПрава/Ext/Module.bsl rename to src/cf/CommonModules/__ОбщегоНазначенияПолныеПрава/Ext/Module.bsl diff --git a/src/CommonModules/__ОбщегоНазначенияСервер.xml b/src/cf/CommonModules/__ОбщегоНазначенияСервер.xml similarity index 100% rename from src/CommonModules/__ОбщегоНазначенияСервер.xml rename to src/cf/CommonModules/__ОбщегоНазначенияСервер.xml diff --git a/src/CommonModules/__ОбщегоНазначенияСервер/Ext/Module.bsl b/src/cf/CommonModules/__ОбщегоНазначенияСервер/Ext/Module.bsl similarity index 100% rename from src/CommonModules/__ОбщегоНазначенияСервер/Ext/Module.bsl rename to src/cf/CommonModules/__ОбщегоНазначенияСервер/Ext/Module.bsl diff --git a/src/CommonModules/__ОбщегоНазначенияСлужебный.xml b/src/cf/CommonModules/__ОбщегоНазначенияСлужебный.xml similarity index 100% rename from src/CommonModules/__ОбщегоНазначенияСлужебный.xml rename to src/cf/CommonModules/__ОбщегоНазначенияСлужебный.xml diff --git a/src/CommonModules/__ОбщегоНазначенияСлужебный/Ext/Module.bsl b/src/cf/CommonModules/__ОбщегоНазначенияСлужебный/Ext/Module.bsl similarity index 100% rename from src/CommonModules/__ОбщегоНазначенияСлужебный/Ext/Module.bsl rename to src/cf/CommonModules/__ОбщегоНазначенияСлужебный/Ext/Module.bsl diff --git a/src/CommonModules/__ОбщегоНазначенияСлужебныйКлиент.xml b/src/cf/CommonModules/__ОбщегоНазначенияСлужебныйКлиент.xml similarity index 100% rename from src/CommonModules/__ОбщегоНазначенияСлужебныйКлиент.xml rename to src/cf/CommonModules/__ОбщегоНазначенияСлужебныйКлиент.xml diff --git a/src/CommonModules/__ОбщегоНазначенияСлужебныйКлиент/Ext/Module.bsl b/src/cf/CommonModules/__ОбщегоНазначенияСлужебныйКлиент/Ext/Module.bsl similarity index 100% rename from src/CommonModules/__ОбщегоНазначенияСлужебныйКлиент/Ext/Module.bsl rename to src/cf/CommonModules/__ОбщегоНазначенияСлужебныйКлиент/Ext/Module.bsl diff --git a/src/CommonModules/__ОбщегоНазначенияСлужебныйКлиентСервер.xml b/src/cf/CommonModules/__ОбщегоНазначенияСлужебныйКлиентСервер.xml similarity index 100% rename from src/CommonModules/__ОбщегоНазначенияСлужебныйКлиентСервер.xml rename to src/cf/CommonModules/__ОбщегоНазначенияСлужебныйКлиентСервер.xml diff --git a/src/CommonModules/__ОбщегоНазначенияСлужебныйКлиентСервер/Ext/Module.bsl b/src/cf/CommonModules/__ОбщегоНазначенияСлужебныйКлиентСервер/Ext/Module.bsl similarity index 100% rename from src/CommonModules/__ОбщегоНазначенияСлужебныйКлиентСервер/Ext/Module.bsl rename to src/cf/CommonModules/__ОбщегоНазначенияСлужебныйКлиентСервер/Ext/Module.bsl diff --git a/src/CommonModules/__ПолучениеФайловИзИнтернета.xml b/src/cf/CommonModules/__ПолучениеФайловИзИнтернета.xml similarity index 100% rename from src/CommonModules/__ПолучениеФайловИзИнтернета.xml rename to src/cf/CommonModules/__ПолучениеФайловИзИнтернета.xml diff --git a/src/CommonModules/__ПолучениеФайловИзИнтернета/Ext/Module.bsl b/src/cf/CommonModules/__ПолучениеФайловИзИнтернета/Ext/Module.bsl similarity index 100% rename from src/CommonModules/__ПолучениеФайловИзИнтернета/Ext/Module.bsl rename to src/cf/CommonModules/__ПолучениеФайловИзИнтернета/Ext/Module.bsl diff --git a/src/CommonModules/__ПолучениеФайловИзИнтернетаСлужебный.xml b/src/cf/CommonModules/__ПолучениеФайловИзИнтернетаСлужебный.xml similarity index 100% rename from src/CommonModules/__ПолучениеФайловИзИнтернетаСлужебный.xml rename to src/cf/CommonModules/__ПолучениеФайловИзИнтернетаСлужебный.xml diff --git a/src/CommonModules/__ПолучениеФайловИзИнтернетаСлужебный/Ext/Module.bsl b/src/cf/CommonModules/__ПолучениеФайловИзИнтернетаСлужебный/Ext/Module.bsl similarity index 100% rename from src/CommonModules/__ПолучениеФайловИзИнтернетаСлужебный/Ext/Module.bsl rename to src/cf/CommonModules/__ПолучениеФайловИзИнтернетаСлужебный/Ext/Module.bsl diff --git a/src/CommonModules/__Пользователи.xml b/src/cf/CommonModules/__Пользователи.xml similarity index 100% rename from src/CommonModules/__Пользователи.xml rename to src/cf/CommonModules/__Пользователи.xml diff --git a/src/CommonModules/__Пользователи/Ext/Module.bsl b/src/cf/CommonModules/__Пользователи/Ext/Module.bsl similarity index 100% rename from src/CommonModules/__Пользователи/Ext/Module.bsl rename to src/cf/CommonModules/__Пользователи/Ext/Module.bsl diff --git a/src/CommonModules/__ПользователиКлиентСервер.xml b/src/cf/CommonModules/__ПользователиКлиентСервер.xml similarity index 100% rename from src/CommonModules/__ПользователиКлиентСервер.xml rename to src/cf/CommonModules/__ПользователиКлиентСервер.xml diff --git a/src/CommonModules/__ПользователиКлиентСервер/Ext/Module.bsl b/src/cf/CommonModules/__ПользователиКлиентСервер/Ext/Module.bsl similarity index 100% rename from src/CommonModules/__ПользователиКлиентСервер/Ext/Module.bsl rename to src/cf/CommonModules/__ПользователиКлиентСервер/Ext/Module.bsl diff --git a/src/CommonModules/__ПользователиСлужебный.xml b/src/cf/CommonModules/__ПользователиСлужебный.xml similarity index 100% rename from src/CommonModules/__ПользователиСлужебный.xml rename to src/cf/CommonModules/__ПользователиСлужебный.xml diff --git a/src/CommonModules/__ПользователиСлужебный/Ext/Module.bsl b/src/cf/CommonModules/__ПользователиСлужебный/Ext/Module.bsl similarity index 100% rename from src/CommonModules/__ПользователиСлужебный/Ext/Module.bsl rename to src/cf/CommonModules/__ПользователиСлужебный/Ext/Module.bsl diff --git a/src/CommonModules/__ПредопределенныеЗначения.xml b/src/cf/CommonModules/__ПредопределенныеЗначения.xml similarity index 100% rename from src/CommonModules/__ПредопределенныеЗначения.xml rename to src/cf/CommonModules/__ПредопределенныеЗначения.xml diff --git a/src/CommonModules/__ПредопределенныеЗначения/Ext/Module.bsl b/src/cf/CommonModules/__ПредопределенныеЗначения/Ext/Module.bsl similarity index 100% rename from src/CommonModules/__ПредопределенныеЗначения/Ext/Module.bsl rename to src/cf/CommonModules/__ПредопределенныеЗначения/Ext/Module.bsl diff --git a/src/CommonModules/__ПредопределенныеЗначенияПереопределяемый.xml b/src/cf/CommonModules/__ПредопределенныеЗначенияПереопределяемый.xml similarity index 100% rename from src/CommonModules/__ПредопределенныеЗначенияПереопределяемый.xml rename to src/cf/CommonModules/__ПредопределенныеЗначенияПереопределяемый.xml diff --git a/src/CommonModules/__ПредопределенныеЗначенияПереопределяемый/Ext/Module.bsl b/src/cf/CommonModules/__ПредопределенныеЗначенияПереопределяемый/Ext/Module.bsl similarity index 100% rename from src/CommonModules/__ПредопределенныеЗначенияПереопределяемый/Ext/Module.bsl rename to src/cf/CommonModules/__ПредопределенныеЗначенияПереопределяемый/Ext/Module.bsl diff --git a/src/CommonModules/__РаботаСДиалогамиКлиент.xml b/src/cf/CommonModules/__РаботаСДиалогамиКлиент.xml similarity index 100% rename from src/CommonModules/__РаботаСДиалогамиКлиент.xml rename to src/cf/CommonModules/__РаботаСДиалогамиКлиент.xml diff --git a/src/CommonModules/__РаботаСДиалогамиКлиент/Ext/Module.bsl b/src/cf/CommonModules/__РаботаСДиалогамиКлиент/Ext/Module.bsl similarity index 100% rename from src/CommonModules/__РаботаСДиалогамиКлиент/Ext/Module.bsl rename to src/cf/CommonModules/__РаботаСДиалогамиКлиент/Ext/Module.bsl diff --git a/src/CommonModules/__РаботаСДиалогамиСервер.xml b/src/cf/CommonModules/__РаботаСДиалогамиСервер.xml similarity index 100% rename from src/CommonModules/__РаботаСДиалогамиСервер.xml rename to src/cf/CommonModules/__РаботаСДиалогамиСервер.xml diff --git a/src/CommonModules/__РаботаСДиалогамиСервер/Ext/Module.bsl b/src/cf/CommonModules/__РаботаСДиалогамиСервер/Ext/Module.bsl similarity index 100% rename from src/CommonModules/__РаботаСДиалогамиСервер/Ext/Module.bsl rename to src/cf/CommonModules/__РаботаСДиалогамиСервер/Ext/Module.bsl diff --git a/src/CommonModules/__РаботаСКоллекциямиКлиентСервер.xml b/src/cf/CommonModules/__РаботаСКоллекциямиКлиентСервер.xml similarity index 100% rename from src/CommonModules/__РаботаСКоллекциямиКлиентСервер.xml rename to src/cf/CommonModules/__РаботаСКоллекциямиКлиентСервер.xml diff --git a/src/CommonModules/__РаботаСКоллекциямиКлиентСервер/Ext/Module.bsl b/src/cf/CommonModules/__РаботаСКоллекциямиКлиентСервер/Ext/Module.bsl similarity index 100% rename from src/CommonModules/__РаботаСКоллекциямиКлиентСервер/Ext/Module.bsl rename to src/cf/CommonModules/__РаботаСКоллекциямиКлиентСервер/Ext/Module.bsl diff --git a/src/CommonModules/__РаботаСФормами.xml b/src/cf/CommonModules/__РаботаСФормами.xml similarity index 100% rename from src/CommonModules/__РаботаСФормами.xml rename to src/cf/CommonModules/__РаботаСФормами.xml diff --git a/src/CommonModules/__РаботаСФормами/Ext/Module.bsl b/src/cf/CommonModules/__РаботаСФормами/Ext/Module.bsl similarity index 100% rename from src/CommonModules/__РаботаСФормами/Ext/Module.bsl rename to src/cf/CommonModules/__РаботаСФормами/Ext/Module.bsl diff --git a/src/CommonModules/__РегламентныеЗаданияСервер.xml b/src/cf/CommonModules/__РегламентныеЗаданияСервер.xml similarity index 100% rename from src/CommonModules/__РегламентныеЗаданияСервер.xml rename to src/cf/CommonModules/__РегламентныеЗаданияСервер.xml diff --git a/src/CommonModules/__РегламентныеЗаданияСервер/Ext/Module.bsl b/src/cf/CommonModules/__РегламентныеЗаданияСервер/Ext/Module.bsl similarity index 100% rename from src/CommonModules/__РегламентныеЗаданияСервер/Ext/Module.bsl rename to src/cf/CommonModules/__РегламентныеЗаданияСервер/Ext/Module.bsl diff --git a/src/CommonModules/__РегламентныеЗаданияСлужебныйСервер.xml b/src/cf/CommonModules/__РегламентныеЗаданияСлужебныйСервер.xml similarity index 100% rename from src/CommonModules/__РегламентныеЗаданияСлужебныйСервер.xml rename to src/cf/CommonModules/__РегламентныеЗаданияСлужебныйСервер.xml diff --git a/src/CommonModules/__РегламентныеЗаданияСлужебныйСервер/Ext/Module.bsl b/src/cf/CommonModules/__РегламентныеЗаданияСлужебныйСервер/Ext/Module.bsl similarity index 100% rename from src/CommonModules/__РегламентныеЗаданияСлужебныйСервер/Ext/Module.bsl rename to src/cf/CommonModules/__РегламентныеЗаданияСлужебныйСервер/Ext/Module.bsl diff --git a/src/CommonModules/__СправочникиОбработкаЗаполнения.xml b/src/cf/CommonModules/__СправочникиОбработкаЗаполнения.xml similarity index 100% rename from src/CommonModules/__СправочникиОбработкаЗаполнения.xml rename to src/cf/CommonModules/__СправочникиОбработкаЗаполнения.xml diff --git a/src/CommonModules/__СправочникиОбработкаЗаполнения/Ext/Module.bsl b/src/cf/CommonModules/__СправочникиОбработкаЗаполнения/Ext/Module.bsl similarity index 100% rename from src/CommonModules/__СправочникиОбработкаЗаполнения/Ext/Module.bsl rename to src/cf/CommonModules/__СправочникиОбработкаЗаполнения/Ext/Module.bsl diff --git a/src/CommonModules/__СправочникиПередЗаписью.xml b/src/cf/CommonModules/__СправочникиПередЗаписью.xml similarity index 100% rename from src/CommonModules/__СправочникиПередЗаписью.xml rename to src/cf/CommonModules/__СправочникиПередЗаписью.xml diff --git a/src/CommonModules/__СправочникиПередЗаписью/Ext/Module.bsl b/src/cf/CommonModules/__СправочникиПередЗаписью/Ext/Module.bsl similarity index 100% rename from src/CommonModules/__СправочникиПередЗаписью/Ext/Module.bsl rename to src/cf/CommonModules/__СправочникиПередЗаписью/Ext/Module.bsl diff --git a/src/CommonModules/__СправочникиПриЗаписи.xml b/src/cf/CommonModules/__СправочникиПриЗаписи.xml similarity index 100% rename from src/CommonModules/__СправочникиПриЗаписи.xml rename to src/cf/CommonModules/__СправочникиПриЗаписи.xml diff --git a/src/CommonModules/__СправочникиПриЗаписи/Ext/Module.bsl b/src/cf/CommonModules/__СправочникиПриЗаписи/Ext/Module.bsl similarity index 100% rename from src/CommonModules/__СправочникиПриЗаписи/Ext/Module.bsl rename to src/cf/CommonModules/__СправочникиПриЗаписи/Ext/Module.bsl diff --git a/src/CommonModules/__СправочникиПриКопировании.xml b/src/cf/CommonModules/__СправочникиПриКопировании.xml similarity index 100% rename from src/CommonModules/__СправочникиПриКопировании.xml rename to src/cf/CommonModules/__СправочникиПриКопировании.xml diff --git a/src/CommonModules/__СправочникиПриКопировании/Ext/Module.bsl b/src/cf/CommonModules/__СправочникиПриКопировании/Ext/Module.bsl similarity index 100% rename from src/CommonModules/__СправочникиПриКопировании/Ext/Module.bsl rename to src/cf/CommonModules/__СправочникиПриКопировании/Ext/Module.bsl diff --git a/src/CommonModules/__СтандартныеПодсистемыПовтИсп.xml b/src/cf/CommonModules/__СтандартныеПодсистемыПовтИсп.xml similarity index 100% rename from src/CommonModules/__СтандартныеПодсистемыПовтИсп.xml rename to src/cf/CommonModules/__СтандартныеПодсистемыПовтИсп.xml diff --git a/src/CommonModules/__СтандартныеПодсистемыПовтИсп/Ext/Module.bsl b/src/cf/CommonModules/__СтандартныеПодсистемыПовтИсп/Ext/Module.bsl similarity index 100% rename from src/CommonModules/__СтандартныеПодсистемыПовтИсп/Ext/Module.bsl rename to src/cf/CommonModules/__СтандартныеПодсистемыПовтИсп/Ext/Module.bsl diff --git a/src/CommonModules/__СтандартныеПодсистемыСлужебныйПовтИсп.xml b/src/cf/CommonModules/__СтандартныеПодсистемыСлужебныйПовтИсп.xml similarity index 100% rename from src/CommonModules/__СтандартныеПодсистемыСлужебныйПовтИсп.xml rename to src/cf/CommonModules/__СтандартныеПодсистемыСлужебныйПовтИсп.xml diff --git a/src/CommonModules/__СтандартныеПодсистемыСлужебныйПовтИсп/Ext/Module.bsl b/src/cf/CommonModules/__СтандартныеПодсистемыСлужебныйПовтИсп/Ext/Module.bsl similarity index 100% rename from src/CommonModules/__СтандартныеПодсистемыСлужебныйПовтИсп/Ext/Module.bsl rename to src/cf/CommonModules/__СтандартныеПодсистемыСлужебныйПовтИсп/Ext/Module.bsl diff --git a/src/CommonModules/__СтроковыеФункцииКлиентСервер.xml b/src/cf/CommonModules/__СтроковыеФункцииКлиентСервер.xml similarity index 100% rename from src/CommonModules/__СтроковыеФункцииКлиентСервер.xml rename to src/cf/CommonModules/__СтроковыеФункцииКлиентСервер.xml diff --git a/src/CommonModules/__СтроковыеФункцииКлиентСервер/Ext/Module.bsl b/src/cf/CommonModules/__СтроковыеФункцииКлиентСервер/Ext/Module.bsl similarity index 100% rename from src/CommonModules/__СтроковыеФункцииКлиентСервер/Ext/Module.bsl rename to src/cf/CommonModules/__СтроковыеФункцииКлиентСервер/Ext/Module.bsl diff --git a/src/CommonModules/__СтроковыеФункцииСлужебныйКлиентСервер.xml b/src/cf/CommonModules/__СтроковыеФункцииСлужебныйКлиентСервер.xml similarity index 100% rename from src/CommonModules/__СтроковыеФункцииСлужебныйКлиентСервер.xml rename to src/cf/CommonModules/__СтроковыеФункцииСлужебныйКлиентСервер.xml diff --git a/src/CommonModules/__СтроковыеФункцииСлужебныйКлиентСервер/Ext/Module.bsl b/src/cf/CommonModules/__СтроковыеФункцииСлужебныйКлиентСервер/Ext/Module.bsl similarity index 100% rename from src/CommonModules/__СтроковыеФункцииСлужебныйКлиентСервер/Ext/Module.bsl rename to src/cf/CommonModules/__СтроковыеФункцииСлужебныйКлиентСервер/Ext/Module.bsl diff --git a/src/CommonModules/__СхемыЗапросов.xml b/src/cf/CommonModules/__СхемыЗапросов.xml similarity index 100% rename from src/CommonModules/__СхемыЗапросов.xml rename to src/cf/CommonModules/__СхемыЗапросов.xml diff --git a/src/CommonModules/__СхемыЗапросов/Ext/Module.bsl b/src/cf/CommonModules/__СхемыЗапросов/Ext/Module.bsl similarity index 100% rename from src/CommonModules/__СхемыЗапросов/Ext/Module.bsl rename to src/cf/CommonModules/__СхемыЗапросов/Ext/Module.bsl diff --git a/src/CommonModules/__ТипСоответствияОбъектовИБПереопределяемый.xml b/src/cf/CommonModules/__ТипСоответствияОбъектовИБПереопределяемый.xml similarity index 100% rename from src/CommonModules/__ТипСоответствияОбъектовИБПереопределяемый.xml rename to src/cf/CommonModules/__ТипСоответствияОбъектовИБПереопределяемый.xml diff --git a/src/CommonModules/__ТипСоответствияОбъектовИБПереопределяемый/Ext/Module.bsl b/src/cf/CommonModules/__ТипСоответствияОбъектовИБПереопределяемый/Ext/Module.bsl similarity index 100% rename from src/CommonModules/__ТипСоответствияОбъектовИБПереопределяемый/Ext/Module.bsl rename to src/cf/CommonModules/__ТипСоответствияОбъектовИБПереопределяемый/Ext/Module.bsl diff --git a/src/CommonPictures/__ПодсистемаУправлениеИнтеграциями.xml b/src/cf/CommonPictures/__ПодсистемаУправлениеИнтеграциями.xml similarity index 100% rename from src/CommonPictures/__ПодсистемаУправлениеИнтеграциями.xml rename to src/cf/CommonPictures/__ПодсистемаУправлениеИнтеграциями.xml diff --git a/src/CommonPictures/__ПодсистемаУправлениеИнтеграциями/Ext/Picture.xml b/src/cf/CommonPictures/__ПодсистемаУправлениеИнтеграциями/Ext/Picture.xml similarity index 100% rename from src/CommonPictures/__ПодсистемаУправлениеИнтеграциями/Ext/Picture.xml rename to src/cf/CommonPictures/__ПодсистемаУправлениеИнтеграциями/Ext/Picture.xml diff --git a/src/CommonPictures/__ПодсистемаУправлениеИнтеграциями/Ext/Picture/Picture.png b/src/cf/CommonPictures/__ПодсистемаУправлениеИнтеграциями/Ext/Picture/Picture.png similarity index 100% rename from src/CommonPictures/__ПодсистемаУправлениеИнтеграциями/Ext/Picture/Picture.png rename to src/cf/CommonPictures/__ПодсистемаУправлениеИнтеграциями/Ext/Picture/Picture.png diff --git a/src/CommonPictures/__Реквизит.xml b/src/cf/CommonPictures/__Реквизит.xml similarity index 100% rename from src/CommonPictures/__Реквизит.xml rename to src/cf/CommonPictures/__Реквизит.xml diff --git a/src/CommonPictures/__Реквизит/Ext/Picture.xml b/src/cf/CommonPictures/__Реквизит/Ext/Picture.xml similarity index 100% rename from src/CommonPictures/__Реквизит/Ext/Picture.xml rename to src/cf/CommonPictures/__Реквизит/Ext/Picture.xml diff --git a/src/CommonPictures/__Реквизит/Ext/Picture/Picture.bmp b/src/cf/CommonPictures/__Реквизит/Ext/Picture/Picture.bmp similarity index 100% rename from src/CommonPictures/__Реквизит/Ext/Picture/Picture.bmp rename to src/cf/CommonPictures/__Реквизит/Ext/Picture/Picture.bmp diff --git a/src/CommonPictures/__Реквизиты.xml b/src/cf/CommonPictures/__Реквизиты.xml similarity index 100% rename from src/CommonPictures/__Реквизиты.xml rename to src/cf/CommonPictures/__Реквизиты.xml diff --git a/src/CommonPictures/__Реквизиты/Ext/Picture.xml b/src/cf/CommonPictures/__Реквизиты/Ext/Picture.xml similarity index 100% rename from src/CommonPictures/__Реквизиты/Ext/Picture.xml rename to src/cf/CommonPictures/__Реквизиты/Ext/Picture.xml diff --git a/src/CommonPictures/__Реквизиты/Ext/Picture/Picture.bmp b/src/cf/CommonPictures/__Реквизиты/Ext/Picture/Picture.bmp similarity index 100% rename from src/CommonPictures/__Реквизиты/Ext/Picture/Picture.bmp rename to src/cf/CommonPictures/__Реквизиты/Ext/Picture/Picture.bmp diff --git a/src/CommonTemplates/__BSLEditor.xml b/src/cf/CommonTemplates/__BSLEditor.xml similarity index 100% rename from src/CommonTemplates/__BSLEditor.xml rename to src/cf/CommonTemplates/__BSLEditor.xml diff --git a/src/CommonTemplates/__BSLEditor/Ext/Template.bin b/src/cf/CommonTemplates/__BSLEditor/Ext/Template.bin similarity index 100% rename from src/CommonTemplates/__BSLEditor/Ext/Template.bin rename to src/cf/CommonTemplates/__BSLEditor/Ext/Template.bin diff --git a/src/CommonTemplates/__JSONEditor.xml b/src/cf/CommonTemplates/__JSONEditor.xml similarity index 100% rename from src/CommonTemplates/__JSONEditor.xml rename to src/cf/CommonTemplates/__JSONEditor.xml diff --git a/src/CommonTemplates/__JSONEditor/Ext/Template.bin b/src/cf/CommonTemplates/__JSONEditor/Ext/Template.bin similarity index 100% rename from src/CommonTemplates/__JSONEditor/Ext/Template.bin rename to src/cf/CommonTemplates/__JSONEditor/Ext/Template.bin diff --git a/src/CommonTemplates/__XMLEditor.xml b/src/cf/CommonTemplates/__XMLEditor.xml similarity index 100% rename from src/CommonTemplates/__XMLEditor.xml rename to src/cf/CommonTemplates/__XMLEditor.xml diff --git a/src/CommonTemplates/__XMLEditor/Ext/Template.bin b/src/cf/CommonTemplates/__XMLEditor/Ext/Template.bin similarity index 100% rename from src/CommonTemplates/__XMLEditor/Ext/Template.bin rename to src/cf/CommonTemplates/__XMLEditor/Ext/Template.bin diff --git a/src/Configuration.xml b/src/cf/Configuration.xml similarity index 100% rename from src/Configuration.xml rename to src/cf/Configuration.xml diff --git a/src/DefinedTypes/ТипыОбъектовСоответствийИБ.xml b/src/cf/DefinedTypes/ТипыОбъектовСоответствийИБ.xml similarity index 100% rename from src/DefinedTypes/ТипыОбъектовСоответствийИБ.xml rename to src/cf/DefinedTypes/ТипыОбъектовСоответствийИБ.xml diff --git a/src/Documents/ДемоРаботаСФормами.xml b/src/cf/Documents/ДемоРаботаСФормами.xml similarity index 100% rename from src/Documents/ДемоРаботаСФормами.xml rename to src/cf/Documents/ДемоРаботаСФормами.xml diff --git a/src/Documents/ДемоРаботаСФормами/Forms/ФормаДокумента.xml b/src/cf/Documents/ДемоРаботаСФормами/Forms/ФормаДокумента.xml similarity index 100% rename from src/Documents/ДемоРаботаСФормами/Forms/ФормаДокумента.xml rename to src/cf/Documents/ДемоРаботаСФормами/Forms/ФормаДокумента.xml diff --git a/src/Documents/ДемоРаботаСФормами/Forms/ФормаДокумента/Ext/Form.xml b/src/cf/Documents/ДемоРаботаСФормами/Forms/ФормаДокумента/Ext/Form.xml similarity index 100% rename from src/Documents/ДемоРаботаСФормами/Forms/ФормаДокумента/Ext/Form.xml rename to src/cf/Documents/ДемоРаботаСФормами/Forms/ФормаДокумента/Ext/Form.xml diff --git a/src/Documents/ДемоРаботаСФормами/Forms/ФормаДокумента/Ext/Form/Module.bsl b/src/cf/Documents/ДемоРаботаСФормами/Forms/ФормаДокумента/Ext/Form/Module.bsl similarity index 100% rename from src/Documents/ДемоРаботаСФормами/Forms/ФормаДокумента/Ext/Form/Module.bsl rename to src/cf/Documents/ДемоРаботаСФормами/Forms/ФормаДокумента/Ext/Form/Module.bsl diff --git a/src/Enums/__КонтекстыВыполненияПользовательскихФункций.xml b/src/cf/Enums/__КонтекстыВыполненияПользовательскихФункций.xml similarity index 100% rename from src/Enums/__КонтекстыВыполненияПользовательскихФункций.xml rename to src/cf/Enums/__КонтекстыВыполненияПользовательскихФункций.xml diff --git a/src/Enums/__СозданОбновлен.xml b/src/cf/Enums/__СозданОбновлен.xml similarity index 100% rename from src/Enums/__СозданОбновлен.xml rename to src/cf/Enums/__СозданОбновлен.xml diff --git a/src/Enums/__СтатусыИнтеграции.xml b/src/cf/Enums/__СтатусыИнтеграции.xml similarity index 100% rename from src/Enums/__СтатусыИнтеграции.xml rename to src/cf/Enums/__СтатусыИнтеграции.xml diff --git a/src/Enums/__ТипыJSON.xml b/src/cf/Enums/__ТипыJSON.xml similarity index 100% rename from src/Enums/__ТипыJSON.xml rename to src/cf/Enums/__ТипыJSON.xml diff --git a/src/Enums/__ФорматыЗапросовИнтеграции.xml b/src/cf/Enums/__ФорматыЗапросовИнтеграции.xml similarity index 100% rename from src/Enums/__ФорматыЗапросовИнтеграции.xml rename to src/cf/Enums/__ФорматыЗапросовИнтеграции.xml diff --git a/src/EventSubscriptions/__ДокументыОбработкаЗаполнения.xml b/src/cf/EventSubscriptions/__ДокументыОбработкаЗаполнения.xml similarity index 100% rename from src/EventSubscriptions/__ДокументыОбработкаЗаполнения.xml rename to src/cf/EventSubscriptions/__ДокументыОбработкаЗаполнения.xml diff --git a/src/EventSubscriptions/__ДокументыОбработкаПроведения.xml b/src/cf/EventSubscriptions/__ДокументыОбработкаПроведения.xml similarity index 100% rename from src/EventSubscriptions/__ДокументыОбработкаПроведения.xml rename to src/cf/EventSubscriptions/__ДокументыОбработкаПроведения.xml diff --git a/src/EventSubscriptions/__ДокументыПередЗаписью.xml b/src/cf/EventSubscriptions/__ДокументыПередЗаписью.xml similarity index 100% rename from src/EventSubscriptions/__ДокументыПередЗаписью.xml rename to src/cf/EventSubscriptions/__ДокументыПередЗаписью.xml diff --git a/src/EventSubscriptions/__ДокументыПриЗаписи.xml b/src/cf/EventSubscriptions/__ДокументыПриЗаписи.xml similarity index 100% rename from src/EventSubscriptions/__ДокументыПриЗаписи.xml rename to src/cf/EventSubscriptions/__ДокументыПриЗаписи.xml diff --git a/src/EventSubscriptions/__ДокументыПриКопировании.xml b/src/cf/EventSubscriptions/__ДокументыПриКопировании.xml similarity index 100% rename from src/EventSubscriptions/__ДокументыПриКопировании.xml rename to src/cf/EventSubscriptions/__ДокументыПриКопировании.xml diff --git a/src/EventSubscriptions/__СправочникиОбработкаЗаполнения.xml b/src/cf/EventSubscriptions/__СправочникиОбработкаЗаполнения.xml similarity index 100% rename from src/EventSubscriptions/__СправочникиОбработкаЗаполнения.xml rename to src/cf/EventSubscriptions/__СправочникиОбработкаЗаполнения.xml diff --git a/src/EventSubscriptions/__СправочникиПередЗаписью.xml b/src/cf/EventSubscriptions/__СправочникиПередЗаписью.xml similarity index 100% rename from src/EventSubscriptions/__СправочникиПередЗаписью.xml rename to src/cf/EventSubscriptions/__СправочникиПередЗаписью.xml diff --git a/src/EventSubscriptions/__СправочникиПриЗаписи.xml b/src/cf/EventSubscriptions/__СправочникиПриЗаписи.xml similarity index 100% rename from src/EventSubscriptions/__СправочникиПриЗаписи.xml rename to src/cf/EventSubscriptions/__СправочникиПриЗаписи.xml diff --git a/src/EventSubscriptions/__СправочникиПриКопировании.xml b/src/cf/EventSubscriptions/__СправочникиПриКопировании.xml similarity index 100% rename from src/EventSubscriptions/__СправочникиПриКопировании.xml rename to src/cf/EventSubscriptions/__СправочникиПриКопировании.xml diff --git a/src/InformationRegisters/__СоответствияОбъектовИБ.xml b/src/cf/InformationRegisters/__СоответствияОбъектовИБ.xml similarity index 100% rename from src/InformationRegisters/__СоответствияОбъектовИБ.xml rename to src/cf/InformationRegisters/__СоответствияОбъектовИБ.xml diff --git a/src/InformationRegisters/__СоответствияОбъектовИБ/Ext/ManagerModule.bsl b/src/cf/InformationRegisters/__СоответствияОбъектовИБ/Ext/ManagerModule.bsl similarity index 100% rename from src/InformationRegisters/__СоответствияОбъектовИБ/Ext/ManagerModule.bsl rename to src/cf/InformationRegisters/__СоответствияОбъектовИБ/Ext/ManagerModule.bsl diff --git a/src/InformationRegisters/__СоответствияОбъектовИБ/Forms/ФормаЗаписи.xml b/src/cf/InformationRegisters/__СоответствияОбъектовИБ/Forms/ФормаЗаписи.xml similarity index 100% rename from src/InformationRegisters/__СоответствияОбъектовИБ/Forms/ФормаЗаписи.xml rename to src/cf/InformationRegisters/__СоответствияОбъектовИБ/Forms/ФормаЗаписи.xml diff --git a/src/InformationRegisters/__СоответствияОбъектовИБ/Forms/ФормаЗаписи/Ext/Form.xml b/src/cf/InformationRegisters/__СоответствияОбъектовИБ/Forms/ФормаЗаписи/Ext/Form.xml similarity index 100% rename from src/InformationRegisters/__СоответствияОбъектовИБ/Forms/ФормаЗаписи/Ext/Form.xml rename to src/cf/InformationRegisters/__СоответствияОбъектовИБ/Forms/ФормаЗаписи/Ext/Form.xml diff --git a/src/InformationRegisters/__СоответствияОбъектовИБ/Forms/ФормаЗаписи/Ext/Form/Module.bsl b/src/cf/InformationRegisters/__СоответствияОбъектовИБ/Forms/ФормаЗаписи/Ext/Form/Module.bsl similarity index 100% rename from src/InformationRegisters/__СоответствияОбъектовИБ/Forms/ФормаЗаписи/Ext/Form/Module.bsl rename to src/cf/InformationRegisters/__СоответствияОбъектовИБ/Forms/ФормаЗаписи/Ext/Form/Module.bsl diff --git a/src/InformationRegisters/__СоответствияОбъектовИБ/Forms/ФормаСписка.xml b/src/cf/InformationRegisters/__СоответствияОбъектовИБ/Forms/ФормаСписка.xml similarity index 100% rename from src/InformationRegisters/__СоответствияОбъектовИБ/Forms/ФормаСписка.xml rename to src/cf/InformationRegisters/__СоответствияОбъектовИБ/Forms/ФормаСписка.xml diff --git a/src/InformationRegisters/__СоответствияОбъектовИБ/Forms/ФормаСписка/Ext/Form.xml b/src/cf/InformationRegisters/__СоответствияОбъектовИБ/Forms/ФормаСписка/Ext/Form.xml similarity index 100% rename from src/InformationRegisters/__СоответствияОбъектовИБ/Forms/ФормаСписка/Ext/Form.xml rename to src/cf/InformationRegisters/__СоответствияОбъектовИБ/Forms/ФормаСписка/Ext/Form.xml diff --git a/src/InformationRegisters/__СоответствияОбъектовИБ/Forms/ФормаСписка/Ext/Form/Module.bsl b/src/cf/InformationRegisters/__СоответствияОбъектовИБ/Forms/ФормаСписка/Ext/Form/Module.bsl similarity index 100% rename from src/InformationRegisters/__СоответствияОбъектовИБ/Forms/ФормаСписка/Ext/Form/Module.bsl rename to src/cf/InformationRegisters/__СоответствияОбъектовИБ/Forms/ФормаСписка/Ext/Form/Module.bsl diff --git a/src/Languages/English.xml b/src/cf/Languages/English.xml similarity index 100% rename from src/Languages/English.xml rename to src/cf/Languages/English.xml diff --git a/src/Languages/Русский.xml b/src/cf/Languages/Русский.xml similarity index 100% rename from src/Languages/Русский.xml rename to src/cf/Languages/Русский.xml diff --git a/src/Roles/__РедактированиеДокументаДемоКаркас.xml b/src/cf/Roles/__РедактированиеДокументаДемоКаркас.xml similarity index 100% rename from src/Roles/__РедактированиеДокументаДемоКаркас.xml rename to src/cf/Roles/__РедактированиеДокументаДемоКаркас.xml diff --git a/src/Roles/__РедактированиеДокументаДемоКаркас/Ext/Rights.xml b/src/cf/Roles/__РедактированиеДокументаДемоКаркас/Ext/Rights.xml similarity index 100% rename from src/Roles/__РедактированиеДокументаДемоКаркас/Ext/Rights.xml rename to src/cf/Roles/__РедактированиеДокументаДемоКаркас/Ext/Rights.xml diff --git a/src/Roles/__РедактированиеНастроекИнтеграции.xml b/src/cf/Roles/__РедактированиеНастроекИнтеграции.xml similarity index 100% rename from src/Roles/__РедактированиеНастроекИнтеграции.xml rename to src/cf/Roles/__РедактированиеНастроекИнтеграции.xml diff --git a/src/Roles/__РедактированиеНастроекИнтеграции/Ext/Rights.xml b/src/cf/Roles/__РедактированиеНастроекИнтеграции/Ext/Rights.xml similarity index 100% rename from src/Roles/__РедактированиеНастроекИнтеграции/Ext/Rights.xml rename to src/cf/Roles/__РедактированиеНастроекИнтеграции/Ext/Rights.xml diff --git a/src/Roles/__РедактированиеНастроекОтбораОбъектов.xml b/src/cf/Roles/__РедактированиеНастроекОтбораОбъектов.xml similarity index 100% rename from src/Roles/__РедактированиеНастроекОтбораОбъектов.xml rename to src/cf/Roles/__РедактированиеНастроекОтбораОбъектов.xml diff --git a/src/Roles/__РедактированиеНастроекОтбораОбъектов/Ext/Rights.xml b/src/cf/Roles/__РедактированиеНастроекОтбораОбъектов/Ext/Rights.xml similarity index 100% rename from src/Roles/__РедактированиеНастроекОтбораОбъектов/Ext/Rights.xml rename to src/cf/Roles/__РедактированиеНастроекОтбораОбъектов/Ext/Rights.xml diff --git a/src/Roles/__РедактированиеПланаВидовХарактеристикПредопределенныеЗначения.xml b/src/cf/Roles/__РедактированиеПланаВидовХарактеристикПредопределенныеЗначения.xml similarity index 100% rename from src/Roles/__РедактированиеПланаВидовХарактеристикПредопределенныеЗначения.xml rename to src/cf/Roles/__РедактированиеПланаВидовХарактеристикПредопределенныеЗначения.xml diff --git a/src/Roles/__РедактированиеПланаВидовХарактеристикПредопределенныеЗначения/Ext/Rights.xml b/src/cf/Roles/__РедактированиеПланаВидовХарактеристикПредопределенныеЗначения/Ext/Rights.xml similarity index 100% rename from src/Roles/__РедактированиеПланаВидовХарактеристикПредопределенныеЗначения/Ext/Rights.xml rename to src/cf/Roles/__РедактированиеПланаВидовХарактеристикПредопределенныеЗначения/Ext/Rights.xml diff --git a/src/Roles/__РедактированиеПользовательскихФункций.xml b/src/cf/Roles/__РедактированиеПользовательскихФункций.xml similarity index 100% rename from src/Roles/__РедактированиеПользовательскихФункций.xml rename to src/cf/Roles/__РедактированиеПользовательскихФункций.xml diff --git a/src/Roles/__РедактированиеПользовательскихФункций/Ext/Rights.xml b/src/cf/Roles/__РедактированиеПользовательскихФункций/Ext/Rights.xml similarity index 100% rename from src/Roles/__РедактированиеПользовательскихФункций/Ext/Rights.xml rename to src/cf/Roles/__РедактированиеПользовательскихФункций/Ext/Rights.xml diff --git a/src/Roles/__РедактированиеРегистраСведенийСоответствияОбъектовИБ.xml b/src/cf/Roles/__РедактированиеРегистраСведенийСоответствияОбъектовИБ.xml similarity index 100% rename from src/Roles/__РедактированиеРегистраСведенийСоответствияОбъектовИБ.xml rename to src/cf/Roles/__РедактированиеРегистраСведенийСоответствияОбъектовИБ.xml diff --git a/src/Roles/__РедактированиеРегистраСведенийСоответствияОбъектовИБ/Ext/Rights.xml b/src/cf/Roles/__РедактированиеРегистраСведенийСоответствияОбъектовИБ/Ext/Rights.xml similarity index 100% rename from src/Roles/__РедактированиеРегистраСведенийСоответствияОбъектовИБ/Ext/Rights.xml rename to src/cf/Roles/__РедактированиеРегистраСведенийСоответствияОбъектовИБ/Ext/Rights.xml diff --git a/src/Roles/__РедактированиеТиповСоответствияОбъектовИБ.xml b/src/cf/Roles/__РедактированиеТиповСоответствияОбъектовИБ.xml similarity index 100% rename from src/Roles/__РедактированиеТиповСоответствияОбъектовИБ.xml rename to src/cf/Roles/__РедактированиеТиповСоответствияОбъектовИБ.xml diff --git a/src/Roles/__РедактированиеТиповСоответствияОбъектовИБ/Ext/Rights.xml b/src/cf/Roles/__РедактированиеТиповСоответствияОбъектовИБ/Ext/Rights.xml similarity index 100% rename from src/Roles/__РедактированиеТиповСоответствияОбъектовИБ/Ext/Rights.xml rename to src/cf/Roles/__РедактированиеТиповСоответствияОбъектовИБ/Ext/Rights.xml diff --git a/src/Roles/__ЧтениеНастроекОтборовОбъектов.xml b/src/cf/Roles/__ЧтениеНастроекОтборовОбъектов.xml similarity index 100% rename from src/Roles/__ЧтениеНастроекОтборовОбъектов.xml rename to src/cf/Roles/__ЧтениеНастроекОтборовОбъектов.xml diff --git a/src/Roles/__ЧтениеНастроекОтборовОбъектов/Ext/Rights.xml b/src/cf/Roles/__ЧтениеНастроекОтборовОбъектов/Ext/Rights.xml similarity index 100% rename from src/Roles/__ЧтениеНастроекОтборовОбъектов/Ext/Rights.xml rename to src/cf/Roles/__ЧтениеНастроекОтборовОбъектов/Ext/Rights.xml diff --git a/src/Roles/__ЧтениеПланаВидовХарактеристикПредопределенныеЗначения.xml b/src/cf/Roles/__ЧтениеПланаВидовХарактеристикПредопределенныеЗначения.xml similarity index 100% rename from src/Roles/__ЧтениеПланаВидовХарактеристикПредопределенныеЗначения.xml rename to src/cf/Roles/__ЧтениеПланаВидовХарактеристикПредопределенныеЗначения.xml diff --git a/src/Roles/__ЧтениеПланаВидовХарактеристикПредопределенныеЗначения/Ext/Rights.xml b/src/cf/Roles/__ЧтениеПланаВидовХарактеристикПредопределенныеЗначения/Ext/Rights.xml similarity index 100% rename from src/Roles/__ЧтениеПланаВидовХарактеристикПредопределенныеЗначения/Ext/Rights.xml rename to src/cf/Roles/__ЧтениеПланаВидовХарактеристикПредопределенныеЗначения/Ext/Rights.xml diff --git a/src/Roles/__ЧтениеРегистраСведенийСоответствияОбъектовИБ.xml b/src/cf/Roles/__ЧтениеРегистраСведенийСоответствияОбъектовИБ.xml similarity index 100% rename from src/Roles/__ЧтениеРегистраСведенийСоответствияОбъектовИБ.xml rename to src/cf/Roles/__ЧтениеРегистраСведенийСоответствияОбъектовИБ.xml diff --git a/src/Roles/__ЧтениеРегистраСведенийСоответствияОбъектовИБ/Ext/Rights.xml b/src/cf/Roles/__ЧтениеРегистраСведенийСоответствияОбъектовИБ/Ext/Rights.xml similarity index 100% rename from src/Roles/__ЧтениеРегистраСведенийСоответствияОбъектовИБ/Ext/Rights.xml rename to src/cf/Roles/__ЧтениеРегистраСведенийСоответствияОбъектовИБ/Ext/Rights.xml diff --git a/src/Roles/__ЧтениеТиповСоответствияОбъектовИБ.xml b/src/cf/Roles/__ЧтениеТиповСоответствияОбъектовИБ.xml similarity index 100% rename from src/Roles/__ЧтениеТиповСоответствияОбъектовИБ.xml rename to src/cf/Roles/__ЧтениеТиповСоответствияОбъектовИБ.xml diff --git a/src/Roles/__ЧтениеТиповСоответствияОбъектовИБ/Ext/Rights.xml b/src/cf/Roles/__ЧтениеТиповСоответствияОбъектовИБ/Ext/Rights.xml similarity index 100% rename from src/Roles/__ЧтениеТиповСоответствияОбъектовИБ/Ext/Rights.xml rename to src/cf/Roles/__ЧтениеТиповСоответствияОбъектовИБ/Ext/Rights.xml diff --git a/src/Roles/АдминистраторСистемы.xml b/src/cf/Roles/АдминистраторСистемы.xml similarity index 100% rename from src/Roles/АдминистраторСистемы.xml rename to src/cf/Roles/АдминистраторСистемы.xml diff --git a/src/Roles/АдминистраторСистемы/Ext/Rights.xml b/src/cf/Roles/АдминистраторСистемы/Ext/Rights.xml similarity index 100% rename from src/Roles/АдминистраторСистемы/Ext/Rights.xml rename to src/cf/Roles/АдминистраторСистемы/Ext/Rights.xml diff --git a/src/Roles/ИнтерактивноеОткрытиеВнешнихОтчетовИОбработок.xml b/src/cf/Roles/ИнтерактивноеОткрытиеВнешнихОтчетовИОбработок.xml similarity index 100% rename from src/Roles/ИнтерактивноеОткрытиеВнешнихОтчетовИОбработок.xml rename to src/cf/Roles/ИнтерактивноеОткрытиеВнешнихОтчетовИОбработок.xml diff --git a/src/Roles/ИнтерактивноеОткрытиеВнешнихОтчетовИОбработок/Ext/Rights.xml b/src/cf/Roles/ИнтерактивноеОткрытиеВнешнихОтчетовИОбработок/Ext/Rights.xml similarity index 100% rename from src/Roles/ИнтерактивноеОткрытиеВнешнихОтчетовИОбработок/Ext/Rights.xml rename to src/cf/Roles/ИнтерактивноеОткрытиеВнешнихОтчетовИОбработок/Ext/Rights.xml diff --git a/src/Roles/ПолныеПрава.xml b/src/cf/Roles/ПолныеПрава.xml similarity index 100% rename from src/Roles/ПолныеПрава.xml rename to src/cf/Roles/ПолныеПрава.xml diff --git a/src/Roles/ПолныеПрава/Ext/Rights.xml b/src/cf/Roles/ПолныеПрава/Ext/Rights.xml similarity index 100% rename from src/Roles/ПолныеПрава/Ext/Rights.xml rename to src/cf/Roles/ПолныеПрава/Ext/Rights.xml diff --git a/src/ScheduledJobs/__ОчисткаИсторииИнтеграции.xml b/src/cf/ScheduledJobs/__ОчисткаИсторииИнтеграции.xml similarity index 100% rename from src/ScheduledJobs/__ОчисткаИсторииИнтеграции.xml rename to src/cf/ScheduledJobs/__ОчисткаИсторииИнтеграции.xml diff --git a/src/ScheduledJobs/__ОчисткаИсторииИнтеграции/Ext/Schedule.xml b/src/cf/ScheduledJobs/__ОчисткаИсторииИнтеграции/Ext/Schedule.xml similarity index 100% rename from src/ScheduledJobs/__ОчисткаИсторииИнтеграции/Ext/Schedule.xml rename to src/cf/ScheduledJobs/__ОчисткаИсторииИнтеграции/Ext/Schedule.xml diff --git a/src/Subsystems/__ЗагрузкаИзТабличногоДокумента.xml b/src/cf/Subsystems/__ЗагрузкаИзТабличногоДокумента.xml similarity index 100% rename from src/Subsystems/__ЗагрузкаИзТабличногоДокумента.xml rename to src/cf/Subsystems/__ЗагрузкаИзТабличногоДокумента.xml diff --git a/src/Subsystems/__МодификацияФорм.xml b/src/cf/Subsystems/__МодификацияФорм.xml similarity index 100% rename from src/Subsystems/__МодификацияФорм.xml rename to src/cf/Subsystems/__МодификацияФорм.xml diff --git a/src/Subsystems/__ОбщегоНазначения.xml b/src/cf/Subsystems/__ОбщегоНазначения.xml similarity index 100% rename from src/Subsystems/__ОбщегоНазначения.xml rename to src/cf/Subsystems/__ОбщегоНазначения.xml diff --git a/src/Subsystems/__ПодпискиНаСобытия.xml b/src/cf/Subsystems/__ПодпискиНаСобытия.xml similarity index 100% rename from src/Subsystems/__ПодпискиНаСобытия.xml rename to src/cf/Subsystems/__ПодпискиНаСобытия.xml diff --git a/src/Subsystems/__ПользовательскиеФункции.xml b/src/cf/Subsystems/__ПользовательскиеФункции.xml similarity index 100% rename from src/Subsystems/__ПользовательскиеФункции.xml rename to src/cf/Subsystems/__ПользовательскиеФункции.xml diff --git a/src/Subsystems/__ПредопределенныеЗначения.xml b/src/cf/Subsystems/__ПредопределенныеЗначения.xml similarity index 100% rename from src/Subsystems/__ПредопределенныеЗначения.xml rename to src/cf/Subsystems/__ПредопределенныеЗначения.xml diff --git a/src/Subsystems/__СоответствиеОбъектовИБ.xml b/src/cf/Subsystems/__СоответствиеОбъектовИБ.xml similarity index 100% rename from src/Subsystems/__СоответствиеОбъектовИБ.xml rename to src/cf/Subsystems/__СоответствиеОбъектовИБ.xml diff --git a/src/Subsystems/__УправлениеИнтеграциями.xml b/src/cf/Subsystems/__УправлениеИнтеграциями.xml similarity index 100% rename from src/Subsystems/__УправлениеИнтеграциями.xml rename to src/cf/Subsystems/__УправлениеИнтеграциями.xml diff --git a/src/cfe/YAXUnit/CommonModules/Мокито.xml b/src/cfe/YAXUnit/CommonModules/Мокито.xml new file mode 100644 index 0000000..ce6dae5 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/Мокито.xml @@ -0,0 +1,23 @@ + + + + + Мокито + + + ru + Мокито + + + + false + true + true + false + true + false + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/Мокито/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/Мокито/Ext/Module.bsl new file mode 100644 index 0000000..25fbf50 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/Мокито/Ext/Module.bsl @@ -0,0 +1,263 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +// BSLLS:CommentedCode-off + +/////////////////////////////////////////////////////////////////// +// Расширяет возможности тестирования, позволяет легко менять логику работы системы: +// +// * подменять результаты работы функций; +// * отключать алгоритмы и проверки; +// * выбрасывать исключения при необходимости; +// * собирать статистику по вызовам методов. +// +// Для работы Мокито необходимо добавить обрабатываемые методы в расширение по следующей схеме: +// +// ```bsl +// &Вместо("ВыполнитьЗапрос") +// Функция ЮТВыполнитьЗапрос(ПараметрыПодключения, Ресурс, HTTPМетод, Параметры, ОписаниеТела, Заголовки) Экспорт +// +// ПараметрыМетода = Мокито.МассивПараметров(ПараметрыПодключения, Ресурс, HTTPМетод, Параметры, ОписаниеТела, Заголовки); +// +// ПрерватьВыполнение = Ложь; +// Результат = МокитоПерехват.АнализВызова(РаботаСHTTP, "ВыполнитьЗапрос", ПараметрыМетода, ПрерватьВыполнение); +// +// Если НЕ ПрерватьВыполнение Тогда +// Возврат ПродолжитьВызов(ПараметрыПодключения, Ресурс, HTTPМетод, Параметры, ОписаниеТела, Заголовки); +// Иначе +// Возврат Результат; +// КонецЕсли; +// +// КонецФункции +// ``` +/////////////////////////////////////////////////////////////////// + +// BSLLS:CommentedCode-on + +#Область ПрограммныйИнтерфейс + +// Начинает обучение (настройку) Мокито. +// После вызова этого метода следует набор правил для подмены логики работы системы. +// +// Параметры: +// Объект - Произвольный - Объект, методы которого хотим подменить. +// СброситьСтарыеНастройки - Булево - Необходимо удалить старые настройки по объекту. +// + `Истина` - все предыдущие настройки мокирования объекта будут забыты. +// + `Ложь` - будет выполнено дообучение объекта. +// +// Возвращаемое значение: +// ОбщийМодуль - см. МокитоОбучение +Функция Обучение(Объект, СброситьСтарыеНастройки = Истина) Экспорт + + Режимы = МокитоСлужебный.РежимыРаботы(); + МокитоСлужебный.УстановитьРежим(Режимы.Обучение); + + Возврат МокитоОбучение.Обучение(Объект, СброситьСтарыеНастройки); + +КонецФункции + +// Переводит мокито в режим прогона тестов. +// +// Важно! Вызов этого метода обязателен перед выполнением тестового прогона метода. +// +// Параметры: +// СброситьСтатистику - Булево - Сбросить статистику прошлых прогонов +Процедура Прогон(СброситьСтатистику = Истина) Экспорт + + Режимы = МокитоСлужебный.РежимыРаботы(); + МокитоСлужебный.УстановитьРежим(Режимы.Тестирование); + + Если СброситьСтатистику Тогда + МокитоСлужебный.ОчиститьСтатистику(); + КонецЕсли; + +КонецПроцедуры + +// Переводит мокито в режим проверки собранной за прогон статистики вызовов. +// +// Параметры: +// Объект - Произвольный - Устанавливает проверяемый объект, вызовы методов которого будем проверять. +// Описание - Строка - Описание проверки, которое будет выведено при возникновении ошибки +// Возвращаемое значение: +// ОбщийМодуль - см. МокитоПроверки +Функция Проверить(Объект, Описание = Неопределено) Экспорт + + Режимы = МокитоСлужебный.РежимыРаботы(); + МокитоСлужебный.УстановитьРежим(Режимы.Проверка); + + Возврат МокитоПроверки.Проверить(Объект, Описание); + +КонецФункции + +// Сбрасывает настройки и повторно инициализирует мокито. +Процедура Сбросить() Экспорт + + МокитоСлужебный.СброситьПараметры(); + +КонецПроцедуры + +#Область КонструкторыПараметров + +// Возвращает маску параметра. Используется при обучении и проверках для фильтрации входных параметров метода. +// +// Указывает, что в метод может передаваться любой параметр. +// Возвращаемое значение: +// см. МокитоСлужебный.ОписаниеМаскиПараметра +Функция ЛюбойПараметр() Экспорт + + МаскаПараметра = МокитоСлужебный.ОписаниеМаскиПараметра(МокитоСлужебный.ТипыУсловийПараметров().Любой, 0); + Возврат МаскаПараметра; + +КонецФункции + +// Возвращает маску параметра. Используется при обучении и проверках для фильтрации входных параметров метода. +// +// Указывает, что в метод может передаваться числовой параметр. +// Возвращаемое значение: +// см. Мокито.ТипизированныйПараметр +Функция ЧисловойПараметр() Экспорт + + Возврат ТипизированныйПараметр(Тип("Число")); + +КонецФункции + +// Возвращает маску параметра. Используется при обучении и проверках для фильтрации входных параметров метода. +// +// Указывает, что в метод может передаваться строковый параметр +// Возвращаемое значение: +// см. Мокито.ТипизированныйПараметр +Функция СтроковыйПараметр() Экспорт + + Возврат ТипизированныйПараметр(Тип("Строка")); + +КонецФункции + +// Возвращает маску параметра. Используется при обучении и проверках для фильтрации входных параметров метода. +// +// Указывает, что в метод может передаваться параметр указанного типа. +// +// Параметры: +// Тип - Тип - Ограничение типа параметра. +// +// Возвращаемое значение: +// Структура - Описание маски параметра: +// * Режим - Строка - Тип маски (значение: `Тип`) +// * Приоритет - Число - Приоритет маски, используется если значение подпадает под несколько масок (значение: `10`) +// * Тип - Тип - Тип, которому должен соответствовать параметр +Функция ТипизированныйПараметр(Тип) Экспорт + + МаскаПараметра = МокитоСлужебный.ОписаниеМаскиПараметра(МокитоСлужебный.ТипыУсловийПараметров().Тип, 10); + МаскаПараметра.Вставить("Тип", Тип); + + Возврат МаскаПараметра; + +КонецФункции + +// Формирует массив параметров. Применяется при обучении (настройке) мокито. +// +// Параметры: +// Параметр1 - Произвольный +// Параметр2 - Произвольный +// Параметр3 - Произвольный +// Параметр4 - Произвольный +// Параметр5 - Произвольный +// Параметр6 - Произвольный +// Параметр7 - Произвольный +// Параметр8 - Произвольный +// Параметр9 - Произвольный +// Параметр10 - Произвольный +// +// Возвращаемое значение: +// Массив из Произвольный - Массив параметров +//@skip-check method-too-many-params +// BSLLS:NumberOfOptionalParams-off +// BSLLS:NumberOfParams-off +Функция МассивПараметров(Параметр1 = "_!%*", + Параметр2 = "_!%*", + Параметр3 = "_!%*", + Параметр4 = "_!%*", + Параметр5 = "_!%*", + Параметр6 = "_!%*", + Параметр7 = "_!%*", + Параметр8 = "_!%*", + Параметр9 = "_!%*", + Параметр10 = "_!%*") Экспорт + + Возврат ЮТКоллекции.ЗначениеВМассиве(Параметр1, + Параметр2, + Параметр3, + Параметр4, + Параметр5, + Параметр6, + Параметр7, + Параметр8, + Параметр9, + Параметр10); + +КонецФункции + +// BSLLS:NumberOfParams-on +// BSLLS:NumberOfOptionalParams-on + +// Возврщает идентификатор значения входного параметра по умолчанию. +// +// Возвращаемое значение: +// Строка +// +// Примеры: +// +// ЮТТесты.ДобавитьТест("Тест1") +// .СПараметрами( +// Мокито.ПараметрПоУмолчанию(), +// 2); // Будет зарегистрирован один тест с параметрами <значение по умолчанию>, 2 +// +Функция ПараметрПоУмолчанию() Экспорт + + Возврат "<[ЗначениеВходногоПараметраПоУмолчанию]>"; + +КонецФункции + +#КонецОбласти + +#КонецОбласти + +#Область СлужебныйПрограммныйИнтерфейс + +#Область УстаревшиеПроцедурыИФункции + +// Устарела. Анализ вызова. +// +// Параметры: +// Объект - Произвольный +// ИмяМетода - Произвольный +// ПараметрыМетода - Произвольный +// ПрерватьВыполнение - Произвольный +// +// Возвращаемое значение: +// Произвольный - Подменный результат работы метода +Функция АнализВызова(Объект, ИмяМетода, ПараметрыМетода, ПрерватьВыполнение) Экспорт + + ЮТМетодыСлужебный.ВызовУстаревшегоМетода("Мокито.АнализВызова", "МокитоПерехват.АнализВызова", "24.03"); + + Возврат МокитоСлужебный.АнализВызова(Объект, ИмяМетода, ПараметрыМетода, ПрерватьВыполнение); + +КонецФункции + +#КонецОбласти + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/МокитоОбучение.xml b/src/cfe/YAXUnit/CommonModules/МокитоОбучение.xml new file mode 100644 index 0000000..296673c --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/МокитоОбучение.xml @@ -0,0 +1,23 @@ + + + + + МокитоОбучение + + + ru + Мокито обучение + + + + false + true + true + false + true + false + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/МокитоОбучение/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/МокитоОбучение/Ext/Module.bsl new file mode 100644 index 0000000..79752e9 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/МокитоОбучение/Ext/Module.bsl @@ -0,0 +1,271 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2023 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +/////////////////////////////////////////////////////////////////// +// Содержит методы для обучения (настройки) Мокито. +// Вы можете настроить какие методы и как подменять, а за которыми просто наблюдать +/////////////////////////////////////////////////////////////////// + +#Область ПрограммныйИнтерфейс + +// Начинает обучение мокито для регистрации правил подмены вызовов методов. +// +// Параметры: +// Объект - Произвольный - Обучаемый объект, с методами которого хотим работать. +// СброситьСтарыеНастройки - Булево - Необходимо удалить старые настройки по объекту. +// + `Истина` - все предыдущие настройки мокирования объекта будут забыты. +// + `Ложь` - будет выполнено дообучение объекта. +// +// Возвращаемое значение: +// ОбщийМодуль - Этот же модуль, для замыкания +Функция Обучение(Объект, СброситьСтарыеНастройки = Истина) Экспорт + + УстановитьПараметрыОбучения(Объект); + МокитоСлужебный.ДобавитьНастройкуПерехватаВызововОбъекта(Объект, СброситьСтарыеНастройки); + + Возврат МокитоОбучение; + +КонецФункции + +// Включает наблюдение за вызовами метода, при необходимости можно настроить фильтр по параметрам вызова. +// +// Параметры: +// ИмяМетода - Строка - Имя метода обучаемого объекта, см. Обучение. +// - Произвольный - Вызов метода обучаемого объекта. +// ПараметрыВызова - Массив из Произвольный - Параметры вызова метода обучаемого объекта. +// Варианты вызова: +// Мокито.Обучение(Произвольный).Когда(Строка, Массив); // Вызов через указание имени метода и параметров +// Мокито.Обучение(Произвольный).Когда(Произвольный); // Вызов через явное выполнение наблюдаемого метода +// +// Возвращаемое значение: +// ОбщийМодуль - Этот же модуль, для замыкания +// Примеры: +// Мокито.Обучение(ОбщегоНазначения).Наблюдать("ЭтоДопустимоеИмяПеременной", Мокито.МассивПараметров("")); +// Мокито.Обучение(ОбщегоНазначения).Наблюдать(ОбщегоНазначения.ЭтоДопустимоеИмяПеременной("")); +Функция Наблюдать(ИмяМетода, ПараметрыВызова = Неопределено) Экспорт + + ЗарегистрироватьПерехватВыражения(ИмяМетода, ПараметрыВызова); + + Возврат МокитоОбучение; + +КонецФункции + +// Задает условие "подмены" поведения метода. +// +// Параметры: +// ИмяМетода - Строка - Имя метода обучаемого объекта. +// - Произвольный - Вызов метода обучаемого объекта. +// ПараметрыВызова - Массив из Произвольный - Параметры вызова метода обучаемого объекта. +// Варианты вызова: +// Мокито.Обучение(Произвольный).Когда(Строка, Массив); // Вызов через указание имени метода и параметров +// Мокито.Обучение(Произвольный).Когда(Произвольный); // Вызов через явное выполнение наблюдаемого метода +// +// Возвращаемое значение: +// ОбщийМодуль - Этот же модуль, для замыкания. +// Примеры: +// Мокито.Обучение(ОбщегоНазначения).Когда("ЭтоДопустимоеИмяПеременной", Мокито.МассивПараметров("")); +// Мокито.Обучение(ОбщегоНазначения).Когда(ОбщегоНазначения.ЭтоДопустимоеИмяПеременной("")); +Функция Когда(ИмяМетода, ПараметрыВызова = Неопределено) Экспорт + + Возврат Наблюдать(ИмяМетода, ПараметрыВызова); + +КонецФункции + +// Указывает, что при соблюдении условий (см. Когда) метод должен вернуть указанный результат. +// +// При этом сам метод не исполняется. +// +// Параметры: +// Результат - Произвольный - Результат, который должен вернуть метод. +// +// Возвращаемое значение: +// ОбщийМодуль - Этот же модуль, для замыкания +Функция Вернуть(Результат) Экспорт + + ЗарегистрироватьРеакцию(Новый Структура("ТипДействия, Результат", МокитоСлужебный.ТипыДействийРеакций().ВернутьРезультат, Результат)); + + Возврат МокитоОбучение; + +КонецФункции + +// Указывает, что при соблюдении условий (см. Когда) метод должен выбросить исключение. +// +// При этом сам метод не исполняется. +// +// Параметры: +// ТекстИсключения - Строка +// +// Возвращаемое значение: +// ОбщийМодуль - Этот же модуль, для замыкания +Функция ВыброситьИсключение(ТекстИсключения) Экспорт + + ЗарегистрироватьРеакцию(Новый Структура("ТипДействия, Ошибка", МокитоСлужебный.ТипыДействийРеакций().ВыброситьИсключение, ТекстИсключения)); + + Возврат МокитоОбучение; + +КонецФункции + +// Указывает, что при соблюдении условий (см. Когда) метод не должен выполняться, его вызов пропускается. +// +// Если это функция, то будет возвращено `Неопределено`. +// +// Возвращаемое значение: +// ОбщийМодуль - Этот же модуль, для замыкания +Функция Пропустить() Экспорт + + ЗарегистрироватьРеакцию(Новый Структура("ТипДействия", МокитоСлужебный.ТипыДействийРеакций().Пропустить)); + + Возврат МокитоОбучение; + +КонецФункции + +// Указывает, что при соблюдении условий (см. Когда) метод должен выполняться. +// Используется для случаев, когда необходимо задать исключения для другого правила на этом методе. +// +// TODO: Нужны примеры +// +// Возвращаемое значение: +// ОбщийМодуль - Этот же модуль, для замыкания +Функция ВыполнитьМетод() Экспорт + + ЗарегистрироватьРеакцию(Новый Структура("ТипДействия", МокитоСлужебный.ТипыДействийРеакций().ВызватьОсновнойМетод)); + + Возврат МокитоОбучение; + +КонецФункции + +// Переводит мокито в режим прогона тестов. +// +// Вызов этого метода обязателен перед выполнением тестового прогона метода. +Процедура Прогон() Экспорт + + Мокито.Прогон(); + +КонецПроцедуры + +#КонецОбласти + +#Область СлужебныеПроцедурыИФункции + +Процедура ЗарегистрироватьПерехватВыражения(ИмяМетода, ПараметрыВызова) + + ПереданаСтруктураВызоваМетода = МокитоСлужебный.ЭтоСтруктураВызоваМетода(ИмяМетода); + + Если ПереданаСтруктураВызоваМетода Тогда + Объект = ИмяМетода.Объект; + Иначе + Объект = ОбучаемыйОбъект(); + КонецЕсли; + + ДанныеПерехвата = МокитоСлужебный.НастройкиПерехватаОбъекта(Объект); + + Если ДанныеПерехвата = Неопределено Тогда + Сообщение = СтрШаблон("Не найдены настройки перехвата для %1. Необходимо предварительно вызвать метод Мокито.Обучение(Объект)", Объект); + ВызватьИсключение Сообщение; + КонецЕсли; + + Если ПереданаСтруктураВызоваМетода Тогда + СтруктураВызоваМетода = ИмяМетода; + Иначе + СтруктураВызоваМетода = МокитоСлужебный.СтруктураВызоваМетода(Объект, ИмяМетода, ПараметрыВызова); + КонецЕсли; + + Методы = ДанныеПерехвата.Методы; + + Если НЕ Методы.Свойство(СтруктураВызоваМетода.ИмяМетода) Тогда + Методы.Вставить(СтруктураВызоваМетода.ИмяМетода, ОписаниеПараметровПерехватаМетода()); + КонецЕсли; + + Реакция = СоздатьОписаниеУсловнойРеакции(СтруктураВызоваМетода); + + РеакцииМетода = Методы[СтруктураВызоваМетода.ИмяМетода].Реакции; + РеакцииМетода.Добавить(Реакция); + + ПараметрыОбучения = ПараметрыОбучения(); + ПараметрыОбучения.РеакцияТекущегоВыражения = Реакция; + ПараметрыОбучения.Реакции = РеакцииМетода; + +КонецПроцедуры + +Функция ОписаниеПараметровПерехватаМетода() + + Возврат Новый Структура("Реакции", Новый Массив); + +КонецФункции + +#Область Реакции + +Функция ОписаниеУсловнойРеакции() + + Возврат Новый Структура("УсловиеРеакции, Действие"); + +КонецФункции + +Функция СоздатьОписаниеУсловнойРеакции(СтруктураВызоваМетода) + + Условия = МокитоСлужебный.УсловиеИзПараметров(СтруктураВызоваМетода.Параметры); + ОписаниеУсловнойРеакции = ОписаниеУсловнойРеакции(); + ОписаниеУсловнойРеакции.УсловиеРеакции = Условия; + Возврат ОписаниеУсловнойРеакции; + +КонецФункции + +#КонецОбласти + +#Область Параметры + +Функция ОбучаемыйОбъект() + + Возврат ПараметрыОбучения().ОбучаемыйОбъект; + +КонецФункции + +Функция ПараметрыОбучения() + + Возврат МокитоСлужебный.Настройки().ПараметрыОбучения; + +КонецФункции + +Процедура УстановитьПараметрыОбучения(Объект) + + ПараметрыОбучения = Новый Структура("ОбучаемыйОбъект, РеакцияТекущегоВыражения, Реакции", Объект, Неопределено); + МокитоСлужебный.Настройки().ПараметрыОбучения = ПараметрыОбучения; + +КонецПроцедуры + +Процедура ЗарегистрироватьРеакцию(Действие) + + Параметры = ПараметрыОбучения(); + + Действие.Вставить("Обработано", Ложь); + + Если Параметры.РеакцияТекущегоВыражения.Действие = Неопределено Тогда + Параметры.РеакцияТекущегоВыражения.Действие = Действие; + Иначе + НоваяРеакция = ОписаниеУсловнойРеакции(); + ЗаполнитьЗначенияСвойств(НоваяРеакция, Параметры.РеакцияТекущегоВыражения); + НоваяРеакция.Действие = Действие; + Параметры.РеакцияТекущегоВыражения = НоваяРеакция; + Параметры.Реакции.Добавить(НоваяРеакция); + КонецЕсли; + +КонецПроцедуры + +#КонецОбласти + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/МокитоПерехват.xml b/src/cfe/YAXUnit/CommonModules/МокитоПерехват.xml new file mode 100644 index 0000000..bfddef5 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/МокитоПерехват.xml @@ -0,0 +1,23 @@ + + + + + МокитоПерехват + + + ru + Мокито перехват + + + + false + true + true + false + true + false + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/МокитоПерехват/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/МокитоПерехват/Ext/Module.bsl new file mode 100644 index 0000000..b5a5c6d --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/МокитоПерехват/Ext/Module.bsl @@ -0,0 +1,37 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область ПрограммныйИнтерфейс + +// Анализ вызова. +// +// Параметры: +// Объект - Произвольный +// ИмяМетода - Произвольный +// ПараметрыМетода - Произвольный +// ПрерватьВыполнение - Произвольный +// +// Возвращаемое значение: +// Произвольный - Подменный результат работы метода +Функция АнализВызова(Объект, ИмяМетода, ПараметрыМетода, ПрерватьВыполнение) Экспорт + + Возврат МокитоСлужебный.АнализВызова(Объект, ИмяМетода, ПараметрыМетода, ПрерватьВыполнение); + +КонецФункции + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/МокитоПроверки.xml b/src/cfe/YAXUnit/CommonModules/МокитоПроверки.xml new file mode 100644 index 0000000..a621892 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/МокитоПроверки.xml @@ -0,0 +1,23 @@ + + + + + МокитоПроверки + + + ru + Мокито проверки + + + + false + true + true + false + true + false + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/МокитоПроверки/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/МокитоПроверки/Ext/Module.bsl new file mode 100644 index 0000000..be7fe14 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/МокитоПроверки/Ext/Module.bsl @@ -0,0 +1,271 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область ПрограммныйИнтерфейс + +// см. Мокито.Проверить +Функция Проверить(Объект, Описание = Неопределено) Экспорт + + УстановитьПараметрыПроверки(Объект, Описание); + Возврат МокитоПроверки; + +КонецФункции + +// Начинает утверждение для проверки количества вызовов метода. +// +// Устанавливает параметры поиска вызовов. +// Параметры: +// ИмяМетода - Строка - Имя метода проверяемого объекта +// - Произвольный - Вызов метода проверяемого объекта +// ПараметрыВызова - Массив из Произвольный - Параметры вызова метода проверяемого объекта, необходим при указании имени метода +// Возвращаемое значение: +// ОбщийМодуль - Этот же модуль, для замыкания +Функция КоличествоВызовов(ИмяМетода = Неопределено, ПараметрыВызова = Неопределено) Экспорт + + СпозиционироватьсяНаМетоде(ИмяМетода, ПараметрыВызова); + + Возврат МокитоПроверки; + +КонецФункции + +// Возвращает информацию о вызовах метода. +// +// Параметры: +// ИмяМетода - Строка - Имя метода проверяемого объекта +// - Произвольный - Вызов метода проверяемого объекта +// ПараметрыВызова - Массив из Произвольный - Параметры вызова метода проверяемого объекта, необходим при указании имени метода +// Возвращаемое значение: +// Массив из см. МокитоСлужебный.СтруктураВызоваМетода - Вызовы метода +Функция Вызовы(ИмяМетода = Неопределено, ПараметрыВызова = Неопределено) Экспорт + + СпозиционироватьсяНаМетоде(ИмяМетода, ПараметрыВызова); + + Возврат СтатистикаВызовов(); + +КонецФункции + +// Проверяет вызовы метода (см. КоличествоВызовов). +// Их количество должно быть равно переданному значение, иначе будет выброшено исключение. +// +// Параметры: +// Количество - Число - Ожидаемое количество вызовов +// Описание - Строка - Описание проверки, необходимо для идентификации упавшей проверки +// +// Возвращаемое значение: +// ОбщийМодуль - Этот же модуль, для замыкания +Функция Равно(Количество, Знач Описание = Неопределено) Экспорт + + Настройки = ПараметрыПроверки(); + + Статистика = СтатистикаВызовов(); + ЮТУтверждения + .Что(Статистика, Настройки.Описание) + .ИмеющееПредставление(ОписаниеПроверяемогоОбъекта()) + .ИмеетДлину(Количество, Описание); + + Возврат МокитоПроверки; + +КонецФункции + +// Проверяет вызовы метода (см. КоличествоВызовов). +// Их количество должно быть больше переданного значения,, иначе будет выброшено исключение. +// Параметры: +// Количество - Число +// Описание - Строка - Описание проверки, необходимо для идентификации упавшей проверки +// +// Возвращаемое значение: +// ОбщийМодуль - Этот же модуль, для замыкания +Функция Больше(Количество, Знач Описание = Неопределено) Экспорт + + Статистика = СтатистикаВызовов(); + ЮТУтверждения + .Что(Статистика, Описание) + .ИмеющееПредставление(ОписаниеПроверяемогоОбъекта()) + .ИмеетДлинуБольше(Количество); + + Возврат МокитоПроверки; + +КонецФункции + +// Проверяет вызовы метода (см. КоличествоВызовов). +// Их количество должно быть меньше переданного значения, иначе будет выброшено исключение. +// Параметры: +// Количество - Число +// Описание - Строка - Описание проверки, необходимо для идентификации упавшей проверки +// +// Возвращаемое значение: +// ОбщийМодуль - Этот же модуль, для замыкания +Функция Меньше(Количество, Знач Описание = Неопределено) Экспорт + + Статистика = СтатистикаВызовов(); + ЮТУтверждения + .Что(Статистика, Описание) + .ИмеющееПредставление(ОписаниеПроверяемогоОбъекта()) + .ИмеетДлинуМеньше(Количество); + + Возврат МокитоПроверки; + +КонецФункции + +// Проверяет, что есть вызовы метода (см. КоличествоВызовов), соответствующие условию. +// Параметры: +// Описание - Строка - Описание проверки, необходимо для идентификации упавшей проверки +// +// Возвращаемое значение: +// ОбщийМодуль - Этот же модуль, для замыкания +Функция Заполнено(Знач Описание = Неопределено) Экспорт + + Статистика = СтатистикаВызовов(Истина); + ЮТУтверждения + .Что(Статистика, Описание) + .ИмеющееПредставление(ОписаниеПроверяемогоОбъекта()) + .Заполнено(); + + Возврат МокитоПроверки; + +КонецФункции + +// Проверяет, что нет вызовов метода (см. КоличествоВызовов), соответствующих условию. +// Параметры: +// Описание - Строка - Описание проверки, необходимо для идентификации упавшей проверки +// +// Возвращаемое значение: +// ОбщийМодуль - Этот же модуль, для замыкания +Функция Пусто(Знач Описание = Неопределено) Экспорт + + Статистика = СтатистикаВызовов(Истина); + ЮТУтверждения + .Что(Статистика, Описание) + .ИмеющееПредставление(ОписаниеПроверяемогоОбъекта()) + .НеЗаполнено(); + + Возврат МокитоПроверки; + +КонецФункции + +#КонецОбласти + +#Область СлужебныеПроцедурыИФункции + +#Область Параметры + +// Параметры проверки. +// +// Возвращаемое значение: +// Структура: +// * ПроверяемыйОбъект - Произвольный +// * СтруктураВызоваМетода - см. МокитоСлужебный.СтруктураВызоваМетода +// * Описание - Строка +Функция ПараметрыПроверки() + + //@skip-check constructor-function-return-section + Возврат МокитоСлужебный.Настройки().ПараметрыПроверки; + +КонецФункции + +Процедура УстановитьПараметрыПроверки(Объект, Описание) + + ПараметрыПроверки = Новый Структура("ПроверяемыйОбъект, Описание, СтруктураВызоваМетода", Объект, Описание); + МокитоСлужебный.Настройки().ПараметрыПроверки = ПараметрыПроверки; + +КонецПроцедуры + +#КонецОбласти + +Функция СтатистикаВызовов(Первый = Ложь) + + Параметры = ПараметрыПроверки(); + СтруктураВызоваМетода = Параметры.СтруктураВызоваМетода; + + ВызовыМетода = МокитоСлужебный.СтатистикаВызовов(СтруктураВызоваМетода.Объект, СтруктураВызоваМетода.ИмяМетода); + + Если ВызовыМетода = Неопределено Тогда + Возврат Новый Массив(); + КонецЕсли; + + Если НЕ ЗначениеЗаполнено(СтруктураВызоваМетода.Параметры) Тогда + Возврат ВызовыМетода; + КонецЕсли; + + УсловияПроверки = МокитоСлужебный.УсловиеИзПараметров(СтруктураВызоваМетода.Параметры); + Результат = Новый Массив(); + + Для Каждого ВызовМетода Из ВызовыМетода Цикл + + Если ВызовМетода.Параметры.Количество() < СтруктураВызоваМетода.Параметры.Количество() Тогда + ВызватьИсключение "Сигнатура метода содержит меньше параметров"; + КонецЕсли; + + КоличествоУсловий = УсловияПроверки.Количество(); + Успешно = Истина; + + Для Инд = 0 По КоличествоУсловий - 1 Цикл + + Параметр = ВызовМетода.Параметры[Инд]; + Условие = УсловияПроверки[Инд]; + + Успешно = МокитоСлужебный.ПроверитьПараметр(Параметр, Условие); + + Если НЕ Успешно Тогда + Прервать; + КонецЕсли; + + КонецЦикла; + + Если Успешно Тогда + Результат.Добавить(ВызовМетода); + Если Первый Тогда + Прервать; + КонецЕсли; + КонецЕсли; + + КонецЦикла; + + Возврат Результат; + +КонецФункции + +Функция ОписаниеПроверяемогоОбъекта() + + СтруктураВызоваМетода = ПараметрыПроверки().СтруктураВызоваМетода; + Объект = СтруктураВызоваМетода.Объект; + ПредставлениеТипа = ЮТТипыДанныхСлужебный.ПредставлениеТипа(ТипЗнч(Объект)); + Возврат СтрШаблон(" - вызовы метода `%1(%2).%3`,", Объект, ПредставлениеТипа, СтруктураВызоваМетода.ИмяМетода); + +КонецФункции + +Процедура СпозиционироватьсяНаМетоде(ИмяМетода = Неопределено, ПараметрыВызова = Неопределено) + + Параметры = ПараметрыПроверки(); + + Если МокитоСлужебный.ЭтоСтруктураВызоваМетода(ИмяМетода) Тогда + СтруктураВызоваМетода = ИмяМетода; + Иначе + Условия = МокитоСлужебный.УсловиеИзПараметров(ПараметрыВызова); + СтруктураВызоваМетода = МокитоСлужебный.СтруктураВызоваМетода(Параметры.ПроверяемыйОбъект, ИмяМетода, Условия); + КонецЕсли; + + Если СтруктураВызоваМетода.Объект <> Параметры.ПроверяемыйОбъект Тогда + ВызватьИсключение "Установлен другой проверяемый объект"; + КонецЕсли; + + Параметры.СтруктураВызоваМетода = СтруктураВызоваМетода; + +КонецПроцедуры + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/МокитоСлужебный.xml b/src/cfe/YAXUnit/CommonModules/МокитоСлужебный.xml new file mode 100644 index 0000000..16cc629 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/МокитоСлужебный.xml @@ -0,0 +1,23 @@ + + + + + МокитоСлужебный + + + ru + Мокито (служебный) + + + + false + true + true + false + true + false + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/МокитоСлужебный/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/МокитоСлужебный/Ext/Module.bsl new file mode 100644 index 0000000..f9bc1f4 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/МокитоСлужебный/Ext/Module.bsl @@ -0,0 +1,714 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область СлужебныйПрограммныйИнтерфейс + +Функция Включен() Экспорт + + ДанныеКонтекста = ЮТКонтекстСлужебный.ДанныеКонтекста(); + Настройки = Неопределено; + Возврат ДанныеКонтекста <> Неопределено И ДанныеКонтекста.Свойство(КлючНастроек(), Настройки) И Настройки <> Неопределено; + +КонецФункции + +Процедура УстановитьРежим(Режим) Экспорт + + Контекст = Настройки(); + Контекст.Режим = Режим; + ОчиститьСлужебныеПараметры(); + +КонецПроцедуры + +// Настройки. +// +// Возвращаемое значение: +// см. НовыеНастройки +Функция Настройки() Экспорт + + Настройки = ЮТКонтекстСлужебный.ЗначениеКонтекста(КлючНастроек()); + + Если Настройки = Неопределено Тогда + ВызватьИсключение "Что-то пошло не так, настройки Мокито не инициализированы"; + КонецЕсли; + + //@skip-check constructor-function-return-section + Возврат Настройки; + +КонецФункции + +#Область СтруктурыДанных + +Функция РежимыРаботы() Экспорт + + Режимы = Новый Структура(); + Режимы.Вставить("Обучение", "Обучение"); + Режимы.Вставить("Тестирование", "Тестирование"); + Режимы.Вставить("Проверка", "Проверка"); + + Возврат Новый ФиксированнаяСтруктура(Режимы); + +КонецФункции + +Функция ТипыДействийРеакций() Экспорт + + ТипыРеакций = Новый Структура(); + ТипыРеакций.Вставить("ВернутьРезультат", "ВернутьРезультат"); + ТипыРеакций.Вставить("ВыброситьИсключение", "ВыброситьИсключение"); + ТипыРеакций.Вставить("Пропустить", "Пропустить"); + ТипыРеакций.Вставить("ВызватьОсновнойМетод", "ВызватьОсновнойМетод"); + + Возврат Новый ФиксированнаяСтруктура(ТипыРеакций); + +КонецФункции + +#КонецОбласти + +Функция АнализВызова(Объект, ИмяМетода, ПараметрыМетода, ПрерватьВыполнение) Экспорт + + ПрерватьВыполнение = Ложь; + + Если НЕ Включен() Тогда + Возврат Неопределено; + КонецЕсли; + + Настройки = Настройки(); + + Если НЕ ЗначениеЗаполнено(Настройки.Перехват) Или Настройки.ТипыПерехватываемыхОбъектов[ТипЗнч(Объект)] = Неопределено Тогда + Возврат Неопределено; + КонецЕсли; + + ПараметрыПерехвата = ДанныеПерехвата(Объект, Настройки); + + Если ПараметрыПерехвата = Неопределено Тогда + Возврат Неопределено; + КонецЕсли; + + РежимыРаботы = РежимыРаботы(); + + СтруктураВызоваМетода = СтруктураВызоваМетода(Объект, ИмяМетода, ПараметрыМетода); + + Если Настройки.Режим = РежимыРаботы.Обучение ИЛИ Настройки.Режим = РежимыРаботы.Проверка Тогда + + ПрерватьВыполнение = Истина; + Возврат СтруктураВызоваМетода; + + ИначеЕсли Настройки.Режим = РежимыРаботы.Тестирование Тогда + + ЗарегистрироватьВызовМетода(Настройки, ПараметрыПерехвата, СтруктураВызоваМетода); + Возврат ПерехватитьВызовМетода(ПараметрыПерехвата, СтруктураВызоваМетода, ПрерватьВыполнение); + + КонецЕсли; + + Возврат Неопределено; + +КонецФункции + +// Структура вызова метода. +// +// Параметры: +// Объект - Произвольный - Объект, которому принадлежит метод +// - Структура - см. СтруктураВызоваМетода +// ИмяМетода - Строка - Имя вызванного метода +// ПараметрыМетода - Массив из Произвольный - Набор параметров, с которыми был вызван метод +// +// Возвращаемое значение: +// Структура - Информация о вызове метода: +// * Объект - Произвольный - Объект, которому принадлежит метод +// * ИмяМетода - Строка - Имя вызванного метода +// * Параметры - Массив из Произвольный - Набор параметров, с которыми был вызван метод +// * Контекст - Строка - Контекст вызова метода +Функция СтруктураВызоваМетода(Объект, ИмяМетода, ПараметрыМетода) Экспорт + + Если ЭтоСтруктураВызоваМетода(Объект) Тогда + Возврат Объект; + КонецЕсли; + + СтруктураВызоваМетода = Новый Структура("Объект, ИмяМетода, Параметры", Объект, ИмяМетода, ПараметрыМетода); + СтруктураВызоваМетода.Вставить("Контекст"); + + //@skip-check constructor-function-return-section + Возврат СтруктураВызоваМетода; + +КонецФункции + +Функция ЭтоСтруктураВызоваМетода(Объект) Экспорт + + Возврат ТипЗнч(Объект) = Тип("Структура"); + +КонецФункции + +#Область Предикаты + +Функция ТипыУсловийПараметров() Экспорт + + Типы = Новый Структура; + Типы.Вставить("Любой", "Любой"); + Типы.Вставить("Значение", "Значение"); + Типы.Вставить("Тип", "Тип"); + Типы.Вставить("ОписаниеТипа", "ОписаниеТипа"); + Типы.Вставить("Предикат", "Предикат"); + + Возврат Новый ФиксированнаяСтруктура(Типы); + +КонецФункции + +// Описание маски параметра. +// +// Параметры: +// ТипУсловия - Строка - см. ТипыУсловийПараметров +// Приоритет - Число - Приоритет маски +// +// Возвращаемое значение: +// Структура - Описание маски параметра: +// * Режим - Строка - см. ТипыУсловийПараметров +// * Приоритет - Число - Приоритет маски, используется если значение подпадает под несколько масок, чем выше приоритет, тем лучше +Функция ОписаниеМаскиПараметра(ТипУсловия, Приоритет) Экспорт + + МаскаПараметра = Новый Структура; + ЮТОбщий.УказатьТипСтруктуры(МаскаПараметра, "МаскаПараметра"); + + МаскаПараметра.Вставить("Режим", ТипУсловия); + МаскаПараметра.Вставить("Приоритет", Приоритет); + + Возврат МаскаПараметра; + +КонецФункции + +Функция ЭтоМаскаПарамера(Параметр) Экспорт + + Возврат ТипЗнч(Параметр) = Тип("Структура") И ЮТОбщий.ТипСтруктуры(Параметр) = "МаскаПараметра"; + +КонецФункции + +Функция ПроверитьПараметр(Параметр, Условие) Экспорт + + ТипыУсловий = ТипыУсловийПараметров(); + Совпадает = Ложь; + + Если Условие.Режим = ТипыУсловий.Любой Тогда + + Совпадает = Истина; + + ИначеЕсли Условие.Режим = ТипыУсловий.Значение Тогда + + Совпадает = ЮТСравнениеСлужебныйКлиентСервер.ЗначенияРавны(Условие.Значение, Параметр); + + ИначеЕсли Условие.Режим = ТипыУсловий.Тип Тогда + + Совпадает = Условие.Тип = ТипЗнч(Параметр); + + ИначеЕсли Условие.Режим = ТипыУсловий.ОписаниеТипа Тогда + + Совпадает = Условие.Тип.СодержитТип(ТипЗнч(Параметр)); + + ИначеЕсли Условие.Режим = ТипыУсловий.Предикат Тогда + + Результат = ЮТПредикатыСлужебныйКлиентСервер.ПроверитьПредикаты(Параметр, Условие.Предикат); + Совпадает = Результат.Успешно; + + КонецЕсли; + + Возврат Совпадает; + +КонецФункции + +#КонецОбласти + +#Область Перехват + +Функция ПараметрыПерехвата() Экспорт + + Возврат Настройки().Перехват; + +КонецФункции + +Функция НастройкиПерехватаОбъекта(Объект) Экспорт + + ПараметрыПерехвата = ПараметрыПерехвата(); + Возврат ПараметрыПерехвата[Объект]; + +КонецФункции + +// Данные перехвата. +// +// Параметры: +// Объект - Произвольный +// Настройки - см. НовыеНастройки +// +// Возвращаемое значение: +// см. ОписаниеПараметровПерехватаОбъекта +Функция ДанныеПерехвата(Объект, Настройки = Неопределено) Экспорт + + Если Настройки = Неопределено Тогда + ПараметрыПерехвата = ПараметрыПерехвата(); + Иначе + ПараметрыПерехвата = Настройки.Перехват; + КонецЕсли; + + Если НЕ ЗначениеЗаполнено(ПараметрыПерехвата) Тогда + Возврат Неопределено; + КонецЕсли; + + Если ТипЗнч(Объект) = Тип("Структура") Тогда + Ключ = Объект.Объект; + Иначе + Ключ = Объект; + КонецЕсли; + + ПараметрыПерехватаОбъекта = ПараметрыПерехвата[Ключ]; + ТипЗначения = ТипЗнч(Ключ); + + Если ПараметрыПерехватаОбъекта = Неопределено Тогда + + Если ЮТТипыДанныхСлужебный.ЭтоТипОбъектаОбработкиОтчета(ТипЗначения) Или ЮТТипыДанныхСлужебный.ЭтоТипНабораЗаписей(ТипЗначения) Тогда + + Менеджер = ЮТОбщий.Менеджер(ТипЗначения); + ПараметрыПерехватаОбъекта = ПараметрыПерехвата[Менеджер]; + + ИначеЕсли ЮТТипыДанныхСлужебный.ЭтоТипОбъекта(ТипЗначения) Тогда + + ПараметрыПерехватаОбъекта = ПараметрыПерехвата[Ключ.Ссылка]; + + Если ПараметрыПерехватаОбъекта = Неопределено Тогда + + Менеджер = ЮТОбщий.Менеджер(ТипЗначения); + ПараметрыПерехватаОбъекта = ПараметрыПерехвата[Менеджер]; + + КонецЕсли; + + КонецЕсли; + + КонецЕсли; + + //@skip-check constructor-function-return-section + Возврат ПараметрыПерехватаОбъекта; + +КонецФункции + +Процедура ДобавитьНастройкуПерехватаВызововОбъекта(Знач Объект, СброситьСтарыеНастройки = Истина) Экспорт + + Настройки = Настройки(); + + Если СброситьСтарыеНастройки ИЛИ Настройки.Перехват[Объект] = Неопределено Тогда + Настройки.Перехват.Вставить(Объект, ОписаниеПараметровПерехватаОбъекта(Объект)); + КонецЕсли; + + ТипОбъекта = ТипЗнч(Объект); + + Настройки.ТипыПерехватываемыхОбъектов.Вставить(ТипОбъекта, Истина); + + Если ЮТТипыДанныхСлужебный.ЭтоСсылочныйТип(ТипОбъекта) Тогда + ТипОбъекта = ЮТТипыДанныхСлужебный.ТипОбъектаСсылки(ТипОбъекта); + Настройки.ТипыПерехватываемыхОбъектов.Вставить(ТипОбъекта, Истина); + ИначеЕсли ЮТТипыДанныхСлужебный.ЭтоТипМенеджера(ТипОбъекта) Тогда +#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ТолстыйКлиентУправляемоеПриложение Тогда + Описание = ЮТМетаданные.ОписаниеОбъектаМетаданных(ТипОбъекта); + + Если Описание <> Неопределено Тогда + + Если Описание.ОписаниеТипа.Ссылочный Или Описание.ОписаниеТипа.ОбработкаОтчет Тогда + ТипОбъекта = Тип(СтрШаблон("%1Объект.%2", Описание.ОписаниеТипа.Имя, Описание.Имя)); + ИначеЕсли Описание.ОписаниеТипа.Регистр Тогда + ТипОбъекта = Тип(СтрШаблон("%1НаборЗаписей.%2", Описание.ОписаниеТипа.Имя, Описание.Имя)); + КонецЕсли; + + Настройки.ТипыПерехватываемыхОбъектов.Вставить(ТипОбъекта, Истина); + + КонецЕсли; +#КонецЕсли + КонецЕсли; + +КонецПроцедуры + +// Описание параметров перехвата объекта. +// +// Параметры: +// Объект - Произвольный - Объект +// +// Возвращаемое значение: +// Структура - Описание параметров перехвата объекта: +// * Объект - Произвольный +// * Методы - Структура +Функция ОписаниеПараметровПерехватаОбъекта(Объект) Экспорт + + Возврат Новый Структура("Объект, Методы", Объект, Новый Структура); + +КонецФункции + +#КонецОбласти + +#Область Статистика + +Функция СтатистикаВызовов(Знач Объект, ИмяМетода) Экспорт + + Вызовы = Настройки().Статистика.Вызовы; + + СтатистикаВызововМетода = Новый Массив(); + Статистика = Вызовы[Объект]; + ТипОбъекта = ТипЗнч(Объект); + + Если Статистика <> Неопределено И Статистика.Свойство(ИмяМетода) Тогда + СтатистикаВызововМетода = Статистика[ИмяМетода]; + ИначеЕсли Статистика = Неопределено И ЮТТипыДанныхСлужебный.ЭтоСсылочныйТип(ТипОбъекта) Тогда + СтатистикаВызововМетода = СтатистикаВызововПоСсылке(Вызовы, Объект, ИмяМетода); + ИначеЕсли ЮТТипыДанныхСлужебный.ЭтоТипМенеджера(ТипОбъекта) Тогда +#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ТолстыйКлиентУправляемоеПриложение Тогда + СтатистикаВызововМетода = СтатистикаВызововПоМенеджеру(Вызовы, Объект, ИмяМетода); +#КонецЕсли + КонецЕсли; + + Возврат СтатистикаВызововМетода; + +КонецФункции + +Процедура ОчиститьСтатистику() Экспорт + + Настройки = Настройки(); + Настройки.Статистика.Вызовы.Очистить(); + +КонецПроцедуры + +#КонецОбласти + +#Область ОбработчикиСобытий + +Процедура ПередКаждымТестом(ОписаниеСобытия) Экспорт + + ИнициализироватьНастройки(); + +КонецПроцедуры + +Процедура ПослеКаждогоТеста(ОписаниеСобытия) Экспорт + + ОчиститьНастройки(); + +КонецПроцедуры + +#КонецОбласти + +#КонецОбласти + +#Область СлужебныеПроцедурыИФункции + +#Область ОбработкаВызовов + +Функция ПерехватитьВызовМетода(ПараметрыПерехвата, СтруктураВызоваМетода, ПрерватьВыполнение) + + Если НЕ ПараметрыПерехвата.Методы.Свойство(СтруктураВызоваМетода.ИмяМетода) Тогда + Возврат Неопределено; + КонецЕсли; + + ПараметрыПерехватаМетода = ПараметрыПерехвата.Методы[СтруктураВызоваМетода.ИмяМетода]; + + Реакция = НайтиРеакцию(ПараметрыПерехватаМетода, СтруктураВызоваМетода); + + Если Реакция = Неопределено ИЛИ Реакция.Действие = Неопределено Тогда + Возврат Неопределено; + КонецЕсли; + + ПрерватьВыполнение = Истина; + + ТипыДействий = ТипыДействийРеакций(); + + Если Реакция.Действие.ТипДействия = ТипыДействий.ВернутьРезультат Тогда + + Реакция.Действие.Обработано = Истина; + Возврат Реакция.Действие.Результат; + + ИначеЕсли Реакция.Действие.ТипДействия = ТипыДействий.ВыброситьИсключение Тогда + + Реакция.Действие.Обработано = Истина; + ВызватьИсключение Реакция.Действие.Ошибка; + + ИначеЕсли Реакция.Действие.ТипДействия = ТипыДействий.Пропустить Тогда + + Реакция.Действие.Обработано = Истина; + Возврат Неопределено; + + ИначеЕсли Реакция.Действие.ТипДействия = ТипыДействий.ВызватьОсновнойМетод Тогда + + Реакция.Действие.Обработано = Истина; + ПрерватьВыполнение = Ложь; + + Иначе + + ВызватьИсключение "Неизвестный тип действия реакции"; + + КонецЕсли; + + Возврат Неопределено; +КонецФункции + +#КонецОбласти + +Функция НайтиРеакцию(ПараметрыПерехватаМетода, СтруктураВызоваМетода) + + ПараметрыВызова = СтруктураВызоваМетода.Параметры; + + ПриоритетыРеакций = Новый Массив(); + ЛучшийПриоритет = 0; + + Для Каждого Реакция Из ПараметрыПерехватаМетода.Реакции Цикл + + ПриоритетРеакции = ПроверитьРеакцию(Реакция, ПараметрыВызова); + + Если ПриоритетРеакции < 0 Тогда + Продолжить; + КонецЕсли; + + ПриоритетыРеакций.Добавить(Новый Структура("Приоритет, Реакция", ПриоритетРеакции, Реакция)); + + Если ЛучшийПриоритет < ПриоритетРеакции Тогда + ЛучшийПриоритет = ПриоритетРеакции; + КонецЕсли; + + КонецЦикла; + + Если ЛучшийПриоритет <= 0 Тогда + Возврат Неопределено; + КонецЕсли; + + Реакция = Неопределено; + + Для Каждого ПриоритетРеакции Из ПриоритетыРеакций Цикл + + Если ПриоритетРеакции.Приоритет = ЛучшийПриоритет Тогда + Реакция = ПриоритетРеакции.Реакция; + Иначе + Продолжить; + КонецЕсли; + + Если Реакция.Действие <> Неопределено И НЕ Реакция.Действие.Обработано Тогда + Прервать; + КонецЕсли; + + КонецЦикла; + + Возврат Реакция; + +КонецФункции + +Функция ПроверитьРеакцию(Реакция, ПараметрыМетода) + + Приоритет = 1; + + Если Реакция.УсловиеРеакции = Неопределено Тогда + Возврат Приоритет; + КонецЕсли; + + Для Инд = 0 По Реакция.УсловиеРеакции.ВГраница() Цикл + + Если НЕ ПроверитьПараметр(ПараметрыМетода[Инд], Реакция.УсловиеРеакции[Инд]) Тогда + + Возврат -1; + + КонецЕсли; + + Приоритет = Приоритет + Реакция.УсловиеРеакции[Инд].Приоритет; + + КонецЦикла; + + Возврат Приоритет; + +КонецФункции + +#Область Настройки + +Процедура ИнициализироватьНастройки() Экспорт + + ЮТКонтекстСлужебный.УстановитьЗначениеКонтекста(КлючНастроек(), НовыеНастройки(), Истина); + +КонецПроцедуры + +// Новые настройки. +// +// Возвращаемое значение: +// Структура - Настройки: +// * Метод - Строка +// * Реакция - Строка +// * Перехват - Соответствие Из Произвольный +// * ТипыПерехватываемыхОбъектов - Соответствие Из Тип +// * Режим - Строка - см. РежимыРаботы +// * Статистика - Структура - Статистика вызовов: +// * Вызовы - Соответствие из Структура +// * ПараметрыОбучения - Структура +// * ПараметрыПроверки - Структура +Функция НовыеНастройки() + + Настройки = Новый Структура; + Настройки.Вставить("Метод"); + Настройки.Вставить("Реакция"); + Настройки.Вставить("Перехват", Новый Соответствие); + Настройки.Вставить("ТипыПерехватываемыхОбъектов", Новый Соответствие); + Настройки.Вставить("Режим", "НеУстановлен"); + Настройки.Вставить("Статистика", Новый Структура("Вызовы", Новый Соответствие)); + + Настройки.Вставить("ПараметрыОбучения", Неопределено); + Настройки.Вставить("ПараметрыПроверки", Неопределено); + + //@skip-check constructor-function-return-section + Возврат Настройки; + +КонецФункции + +Процедура ОчиститьНастройки() Экспорт + + ЮТКонтекстСлужебный.УстановитьЗначениеКонтекста(КлючНастроек(), Неопределено); + +КонецПроцедуры + +Процедура СброситьПараметры() Экспорт + + ИнициализироватьНастройки(); + +КонецПроцедуры + +Функция КлючНастроек() + + Возврат "Mockito"; + +КонецФункции + +Процедура ОчиститьСлужебныеПараметры() + + Настройки = Настройки(); + + Настройки.ПараметрыОбучения = Неопределено; + Настройки.ПараметрыПроверки = Неопределено; + +КонецПроцедуры + +#КонецОбласти + +Функция УсловиеИзПараметров(Параметры) Экспорт + + Если Параметры = Неопределено Тогда + Возврат Неопределено; + КонецЕсли; + + Условия = Новый Массив; + + ТипыУсловий = ТипыУсловийПараметров(); + + Для Каждого Параметр Из Параметры Цикл + + Если ЭтоМаскаПарамера(Параметр) Тогда + + Условия.Добавить(Параметр); + + ИначеЕсли ЮТПредикатыСлужебныйКлиентСервер.ЭтоПредикат(Параметр) Тогда + + Маска = ОписаниеМаскиПараметра(ТипыУсловий.Предикат, 90); + Маска.Вставить("Предикат", ЮТПредикатыСлужебныйКлиентСервер.НаборПредикатов(Параметр)); + Условия.Добавить(Маска); + + Иначе + + Маска = ОписаниеМаскиПараметра(ТипыУсловий.Значение, 100); + Маска.Вставить("Значение", Параметр); + Условия.Добавить(Маска); + + КонецЕсли; + + КонецЦикла; + + Возврат Условия; + +КонецФункции + +#Область Статистика + +// Зарегистрировать вызов метода. +// +// Параметры: +// Настройки - см. ИнициализироватьНастройки +// ПараметрыПерехвата - см. ДанныеПерехвата +// СтруктураВызоваМетода - см. СтруктураВызоваМетода +Процедура ЗарегистрироватьВызовМетода(Настройки, ПараметрыПерехвата, СтруктураВызоваМетода) + + Объект = СтруктураВызоваМетода.Объект; + ИмяМетода = СтруктураВызоваМетода.ИмяМетода; + Статистика = Настройки.Статистика.Вызовы[Объект]; + + Если Статистика = Неопределено Тогда + + Статистика = Новый Структура; + Настройки.Статистика.Вызовы.Вставить(Объект, Статистика); + + КонецЕсли; + + Если НЕ Статистика.Свойство(ИмяМетода) Тогда + + Статистика.Вставить(ИмяМетода, Новый Массив); + + КонецЕсли; + + Статистика[ИмяМетода].Добавить(СтруктураВызоваМетода); + +КонецПроцедуры + +Функция СтатистикаВызововПоСсылке(Вызовы, Ссылка, ИмяМетода) + + СтатистикаВызововМетода = Новый Массив(); + ТипОбъекта = ЮТТипыДанныхСлужебный.ТипОбъектаСсылки(ТипЗнч(Ссылка)); + + Для Каждого Элемент Из Вызовы Цикл + ПодходящийЭлемент = ТипЗнч(Элемент.Ключ) = ТипОбъекта + И Элемент.Ключ.Ссылка = Ссылка + И Элемент.Значение.Свойство(ИмяМетода); + Если ПодходящийЭлемент Тогда + ЮТКоллекции.ДополнитьМассив(СтатистикаВызововМетода, Элемент.Значение[ИмяМетода]); + КонецЕсли; + КонецЦикла; + + Возврат СтатистикаВызововМетода; + +КонецФункции + +#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ТолстыйКлиентУправляемоеПриложение Тогда +Функция СтатистикаВызововПоМенеджеру(Вызовы, Менеджер, ИмяМетода) + + СтатистикаВызововМетода = Новый Массив(); + Описание = ЮТМетаданные.ОписаниеОбъектаМетаданных(Менеджер); + + Если Описание = Неопределено Тогда + Возврат СтатистикаВызововМетода; + КонецЕсли; + + Если Описание.ОписаниеТипа.Ссылочный Или Описание.ОписаниеТипа.ОбработкаОтчет Тогда + ТипОбъекта = Тип(СтрШаблон("%1Объект.%2", Описание.ОписаниеТипа.Имя, Описание.Имя)); + ИначеЕсли Описание.ОписаниеТипа.Регистр Тогда + ТипОбъекта = Тип(СтрШаблон("%1НаборЗаписей.%2", Описание.ОписаниеТипа.Имя, Описание.Имя)); + КонецЕсли; + + Для Каждого Элемент Из Вызовы Цикл + ПодходящийЭлемент = ТипЗнч(Элемент.Ключ) = ТипОбъекта + И Элемент.Значение.Свойство(ИмяМетода); + Если ПодходящийЭлемент Тогда + ЮТКоллекции.ДополнитьМассив(СтатистикаВызововМетода, Элемент.Значение[ИмяМетода]); + КонецЕсли; + КонецЦикла; + + Возврат СтатистикаВызововМетода; + +КонецФункции +#КонецЕсли + +#КонецОбласти + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ОМ_КоннекторHTTP.xml b/src/cfe/YAXUnit/CommonModules/ОМ_КоннекторHTTP.xml new file mode 100644 index 0000000..ecac04a --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ОМ_КоннекторHTTP.xml @@ -0,0 +1,23 @@ + + + + + ОМ_КоннекторHTTP + + + ru + О м коннектор HTTP + + + + false + false + true + false + false + false + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ОМ_КоннекторHTTP/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ОМ_КоннекторHTTP/Ext/Module.bsl new file mode 100644 index 0000000..13e805e --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ОМ_КоннекторHTTP/Ext/Module.bsl @@ -0,0 +1,24 @@ +#Область СлужебныйПрограммныйИнтерфейс + +//Используем мок ЮТест.Данные().HTTPСервисЗапрос + +// Регистрация теста в тестовой системе +Процедура ИсполняемыеСценарии() Экспорт + + // Добавляем тест 'ПроверкаМетодаЗапроса' в набор тестов + ЮТТесты.ДобавитьТест("ПроверкаМетодаЗапроса"); + +КонецПроцедуры + +// Процедура тестирования метода HTTP-запроса +Процедура ПроверкаМетодаЗапроса() Экспорт + + // Создание объекта HTTP-запроса с указанием метода GET + Запрос = ЮТест.Данные().HTTPСервисЗапрос().Метод("GET"); + + // Проверка, что метод запроса установлен корректно + ЮТест.ОжидаетЧто(Запрос.HTTPМетод).Равно("GET"); + +КонецПроцедуры + +#КонецОбласти \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ОМ_ОбщегоНазаначенияСервер.xml b/src/cfe/YAXUnit/CommonModules/ОМ_ОбщегоНазаначенияСервер.xml new file mode 100644 index 0000000..156e6a6 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ОМ_ОбщегоНазаначенияСервер.xml @@ -0,0 +1,23 @@ + + + + + ОМ_ОбщегоНазаначенияСервер + + + ru + О м общего назаначения сервер + + + + false + false + true + false + false + false + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ОМ_ОбщегоНазаначенияСервер/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ОМ_ОбщегоНазаначенияСервер/Ext/Module.bsl new file mode 100644 index 0000000..9a104e5 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ОМ_ОбщегоНазаначенияСервер/Ext/Module.bsl @@ -0,0 +1,83 @@ +#Область СлужебныйПрограммныйИнтерфейс + +Процедура ИсполняемыеСценарии() Экспорт + + ЮТТесты + .ДобавитьТестовыйНабор("Тесты функции ОписаниеТипаЧисло") + .ДобавитьТест("ТестДолженСоздатьТипЧисло") + .ДобавитьТест("ТестДолженВернутьОписаниеЧислаСКорректнымЗнаком") + .ДобавитьТест("ТестДолженУстановитьЗнакЛюбойПриОтсутствииЯвнойУказки"); + + ЮТТесты.ДобавитьТест("ТестПолученияТаблицыДатЗаПериод"); + + +КонецПроцедуры + +#КонецОбласти + + +#Область Тесты + +Процедура ТестДолженСоздатьТипЧисло() Экспорт + + Описание = __ОбщегоНазначенияСервер.ОписаниеТипаЧисло(10, 2, ДопустимыйЗнак.Неотрицательный); + ЮТест.ОжидаетЧто(Тип(Описание)).Равно(Тип("Число")); + +КонецПроцедуры + +Процедура ТестДолженВернутьОписаниеЧислаСКорректнымЗнаком() Экспорт + + Описание = __ОбщегоНазначенияСервер.ОписаниеТипаЧисло(10, 2, ДопустимыйЗнак.Неотрицательный); + Проверка = Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(10, 2, ДопустимыйЗнак.Неотрицательный)); + + ЮТест.ОжидаетЧто(Проверка).Равно(Проверка); + +КонецПроцедуры + +Процедура ТестДолженУстановитьЗнакЛюбойПриОтсутствииЯвнойУказки() Экспорт + + Описание = __ОбщегоНазначенияСервер.ОписаниеТипаЧисло(10, 2); + Проверка = __ОбщегоНазначенияСервер.ОписаниеТипаЧисло(10, 2, ДопустимыйЗнак.Любой); + + ЮТест.ОжидаетЧто(Описание).Равно(Проверка); + +КонецПроцедуры + +Процедура ТестПолученияТаблицыДатЗаПериод() Экспорт + + НачалоПериода = '20200101'; + ОкончаниеПериода = '20200110'; + Интервал = "День"; + + Результат = __ОбщегоНазначенияСервер.ПолучитьТаблицуДатЗаПериод(НачалоПериода, ОкончаниеПериода, Интервал); + + ОжидаемыйРезультат = Новый ТаблицаЗначений; + ОжидаемыйРезультат.Колонки.Добавить("Период", Новый ОписаниеТипов("Дата")); + ДобавитьСтрокуВТаблицу(ОжидаемыйРезультат, '20200101'); + ДобавитьСтрокуВТаблицу(ОжидаемыйРезультат, '20200102'); + ДобавитьСтрокуВТаблицу(ОжидаемыйРезультат, '20200103'); + ДобавитьСтрокуВТаблицу(ОжидаемыйРезультат, '20200104'); + ДобавитьСтрокуВТаблицу(ОжидаемыйРезультат, '20200105'); + ДобавитьСтрокуВТаблицу(ОжидаемыйРезультат, '20200106'); + ДобавитьСтрокуВТаблицу(ОжидаемыйРезультат, '20200107'); + ДобавитьСтрокуВТаблицу(ОжидаемыйРезультат, '20200108'); + ДобавитьСтрокуВТаблицу(ОжидаемыйРезультат, '20200109'); + ДобавитьСтрокуВТаблицу(ОжидаемыйРезультат, '20200110'); + + ЮТест.ОжидаетЧто(Результат.Количество()).Равно(ОжидаемыйРезультат.Количество()); + + Для каждого Строка Из Результат Цикл + ЮТест.ОжидаетЧто(Строка.Период).Равно(ОжидаемыйРезультат[Результат.Индекс(Строка)].Период); + КонецЦикла; + +КонецПроцедуры + +Процедура ДобавитьСтрокуВТаблицу(Таблица, Дата) Экспорт + + Строка = Таблица.Добавить(); + Строка.Период = Дата; + +КонецПроцедуры + +#КонецОбласти + diff --git a/src/cfe/YAXUnit/CommonModules/ЮТАсинхроннаяОбработкаСлужебныйКлиент.xml b/src/cfe/YAXUnit/CommonModules/ЮТАсинхроннаяОбработкаСлужебныйКлиент.xml new file mode 100644 index 0000000..1a24a9d --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТАсинхроннаяОбработкаСлужебныйКлиент.xml @@ -0,0 +1,23 @@ + + + + + ЮТАсинхроннаяОбработкаСлужебныйКлиент + + + ru + Асинхронная обработка служебный + + + + false + true + false + false + true + false + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТАсинхроннаяОбработкаСлужебныйКлиент/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТАсинхроннаяОбработкаСлужебныйКлиент/Ext/Module.bsl new file mode 100644 index 0000000..655790a --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТАсинхроннаяОбработкаСлужебныйКлиент/Ext/Module.bsl @@ -0,0 +1,100 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2023 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область СлужебныйПрограммныйИнтерфейс + +Процедура ВызватьОбработчик(Обработчик, Результат = Неопределено) Экспорт + + Если Обработчик <> Неопределено Тогда + ВыполнитьОбработкуОповещения(Обработчик, Результат); + КонецЕсли; + +КонецПроцедуры + +Процедура ВызватьСледующийОбработчик(ПараметрыИсполнения, Результат = Неопределено) Экспорт + + Обработчик = СледующийОбработчик(ПараметрыИсполнения); + ЮТЛогирование.Отладка("Вызов обработчика исполнителя: " + Обработчик.ИмяПроцедуры); + ВызватьОбработчик(Обработчик, Результат); + +КонецПроцедуры + +Функция СледующийОбработчик(ПараметрыИсполнения) Экспорт + + ПараметрыИсполнения.ИндексСледующегоОбработчика = ПараметрыИсполнения.ИндексСледующегоОбработчика + 1; + Обработчик = ПараметрыИсполнения.Цепочка[ПараметрыИсполнения.ИндексСледующегоОбработчика]; + ЮТЛогирование.Отладка("Следующий обработчик исполнителя: " + Обработчик.ИмяПроцедуры); + + Возврат Обработчик; + +КонецФункции + +Функция ТекущийОбработчик(ПараметрыИсполнения) Экспорт + + Возврат ПараметрыИсполнения.Цепочка[ПараметрыИсполнения.ИндексСледующегоОбработчика]; + +КонецФункции + + Процедура ДобавитьОбработчикЦепочки(ПараметрыИсполнения, Модуль, ИмяМетода) Экспорт + + Обработчик = Новый ОписаниеОповещения(ИмяМетода, Модуль, ПараметрыИсполнения); + ПараметрыИсполнения.Цепочка.Добавить(Обработчик); + +КонецПроцедуры + +Функция ЦепочкаАсинхроннойОбработки() Экспорт + + Параметры = Новый Структура(); + Параметры.Вставить("Цепочка", Новый Массив()); + Параметры.Вставить("ИндексСледующегоОбработчика", -1); + + Возврат Параметры; + +КонецФункции + +Функция НовыйПустойОбработчик(КоличествоПараметров = 1) Экспорт + + МаксимальноеДопустимоеЧислоПараметров = 3; + + Если КоличествоПараметров >= 1 И КоличествоПараметров <= МаксимальноеДопустимоеЧислоПараметров Тогда + Возврат Новый ОписаниеОповещения("ПустойОбработчик" + КоличествоПараметров, ЭтотОбъект); + Иначе + ВызватьИсключение СтрШаблон("Пустой обработчик с %1 параметрами не реализован", КоличествоПараметров); + КонецЕсли; + +КонецФункции + +//@skip-check module-empty-method +//@skip-check doc-comment-parameter-section +Процедура ПустойОбработчик1(Параметр1) Экспорт + +КонецПроцедуры + +//@skip-check module-empty-method +//@skip-check doc-comment-parameter-section +Процедура ПустойОбработчик2(Параметр1, Параметр2) Экспорт + +КонецПроцедуры + +//@skip-check module-empty-method +//@skip-check doc-comment-parameter-section +Процедура ПустойОбработчик3(Параметр1, Параметр2, Параметр3) Экспорт + +КонецПроцедуры + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТЗапросы.xml b/src/cfe/YAXUnit/CommonModules/ЮТЗапросы.xml new file mode 100644 index 0000000..2b5f853 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТЗапросы.xml @@ -0,0 +1,23 @@ + + + + + ЮТЗапросы + + + ru + Запросы + + + + false + true + true + false + true + false + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТЗапросы/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТЗапросы/Ext/Module.bsl new file mode 100644 index 0000000..5bc5a6a --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТЗапросы/Ext/Module.bsl @@ -0,0 +1,238 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +/////////////////////////////////////////////////////////////////// +// Расширяет возможности тестирования, +// позволяет в упрощенной форме получать данны из информационной базы +// как с сервера так и с клиента. +/////////////////////////////////////////////////////////////////// +#Область ПрограммныйИнтерфейс + +// Возвращает значения реквизитов ссылки +// +// Параметры: +// Ссылка - ЛюбаяСсылка +// ИменаРеквизитов - Строка - Имена получаемых реквизитов, разделенные запятой. +// Важно, нельзя указывать реквизиты через точку. +// +// Возвращаемое значение: +// Структура Из Произвольный - Значения реквизитов ссылки +Функция ЗначенияРеквизитов(Ссылка, ИменаРеквизитов) Экспорт + + //@skip-check constructor-function-return-section + Возврат ЮТЗапросыСлужебныйВызовСервера.ЗначенияРеквизитов(Ссылка, ИменаРеквизитов, Ложь); + +КонецФункции + +// Возвращает значение реквизита ссылки +// +// Параметры: +// Ссылка - ЛюбаяСсылка +// ИмяРеквизита - Строка - Имя получаемого реквизита, можно указать путь к вложенному реквизиту через точку +// +// Возвращаемое значение: +// Произвольный - Значение реквизита ссылки +Функция ЗначениеРеквизита(Ссылка, ИмяРеквизита) Экспорт + + Возврат ЮТЗапросыСлужебныйВызовСервера.ЗначенияРеквизитов(Ссылка, ИмяРеквизита, Истина); + +КонецФункции + +// Возвращает первую запись таблицы соответствующую условиям +// +// Параметры: +// ИмяТаблицы - Строка - Имя таблицы базы +// Предикат - Массив из см. ЮТФабрика.ВыражениеПредиката - Набор условий, см. ЮТПредикаты.Получить +// - см. ЮТФабрика.ВыражениеПредиката +// - ОбщийМодуль - Модуль настройки предикатов, см. ЮТест.Предикат +// - Неопределено - Проверит, что таблица не пустая +// Возвращаемое значение: +// Структура, Неопределено - Содержит все данные записи, включая табличный части +Функция Запись(ИмяТаблицы, Предикат) Экспорт + + ОписаниеЗапроса = ЮТЗапросыСлужебныйКлиентСервер.ОписаниеЗапроса(ИмяТаблицы, Предикат, "*"); + //@skip-check constructor-function-return-section + Возврат ЮТЗапросыСлужебныйВызовСервера.Записи(ОписаниеЗапроса, Истина); + +КонецФункции + +// Возвращает записи таблицы соответствующую условиям +// +// Параметры: +// ИмяТаблицы - Строка - Имя таблицы базы +// Предикат - Массив из см. ЮТФабрика.ВыражениеПредиката - Набор условий, см. ЮТПредикаты.Получить +// - см. ЮТФабрика.ВыражениеПредиката +// - ОбщийМодуль - Модуль настройки предикатов, см. ЮТест.Предикат +// - Неопределено - Проверит, что таблица не пустая +// Возвращаемое значение: +// Массив из Структура - Найденные записи, включая табличный части +Функция Записи(ИмяТаблицы, Предикат) Экспорт + + ОписаниеЗапроса = ЮТЗапросыСлужебныйКлиентСервер.ОписаниеЗапроса(ИмяТаблицы, Предикат, "*"); + Возврат ЮТЗапросыСлужебныйВызовСервера.Записи(ОписаниеЗапроса, Ложь); + +КонецФункции + +// Возвращает значения реквизитов первой записи таблицы, соответствующей условиям +// +// Параметры: +// ИмяТаблицы - Строка +// Предикат - Массив из см. ЮТФабрика.ВыражениеПредиката - Набор условий, см. ЮТПредикаты.Получить +// - см. ЮТФабрика.ВыражениеПредиката +// - ОбщийМодуль - Модуль настройки предикатов, см. ЮТест.Предикат +// ИменаРеквизитов - Строка - Имена получаемых реквизитов +// +// Возвращаемое значение: +// Произвольный - Значение реквизита записи +// +Функция ЗначенияРеквизитовЗаписи(ИмяТаблицы, Предикат, ИменаРеквизитов) Экспорт + + ОписаниеЗапроса = ЮТЗапросыСлужебныйКлиентСервер.ОписаниеЗапроса(ИмяТаблицы, Предикат, ИменаРеквизитов); + Возврат ЮТЗапросыСлужебныйВызовСервера.ЗначенияРеквизитовЗаписи(ОписаниеЗапроса, Ложь); + +КонецФункции + +// Возвращает значение реквизита первой записи таблицы, соответствующей условиям +// +// Параметры: +// ИмяТаблицы - Строка +// Предикат - Массив из см. ЮТФабрика.ВыражениеПредиката - Набор условий, см. ЮТПредикаты.Получить +// - см. ЮТФабрика.ВыражениеПредиката +// - ОбщийМодуль - Модуль настройки предикатов, см. ЮТест.Предикат +// ИмяРеквизита - Строка - Имя получаемого реквизита +// +// Возвращаемое значение: +// Структура Из Произвольный - Значения реквизитов записи +// +Функция ЗначениеРеквизитаЗаписи(ИмяТаблицы, Предикат, ИмяРеквизита) Экспорт + + ОписаниеЗапроса = ЮТЗапросыСлужебныйКлиентСервер.ОписаниеЗапроса(ИмяТаблицы, Предикат, ИмяРеквизита); + //@skip-check constructor-function-return-section + Возврат ЮТЗапросыСлужебныйВызовСервера.ЗначенияРеквизитовЗаписи(ОписаниеЗапроса, Истина); + +КонецФункции + +// Вернет признак содержит ли таблица записи удовлетворяющие переданным условиям +// +// Параметры: +// ИмяТаблицы - Строка - Имя таблицы базы +// Предикат - Массив из см. ЮТФабрика.ВыражениеПредиката - Набор условий, см. ЮТПредикаты.Получить +// - см. ЮТФабрика.ВыражениеПредиката +// - ОбщийМодуль - Модуль настройки предикатов, см. ЮТест.Предикат +// - Неопределено - Проверит, что таблица не пустая +// Возвращаемое значение: +// Булево - Таблица содержит записи +Функция ТаблицаСодержитЗаписи(ИмяТаблицы, Предикат = Неопределено) Экспорт + + ОписаниеЗапроса = ЮТЗапросыСлужебныйКлиентСервер.ОписаниеЗапроса(ИмяТаблицы, Предикат); + Возврат НЕ РезультатПустой(ОписаниеЗапроса); + +КонецФункции + +// Возвращает результат выполнения простого запроса. +// +// Параметры: +// ОписаниеЗапроса - см. ОписаниеЗапроса +// +// Возвращаемое значение: +// - ТаблицаЗначений - Результат запроса для сервера +// - Массив из Структура - Результат запроса для клиента +Функция РезультатЗапроса(ОписаниеЗапроса) Экспорт + +#Если Клиент Тогда + Возврат ЮТЗапросыСлужебныйВызовСервера.РезультатЗапроса(ОписаниеЗапроса, Истина); +#Иначе + Возврат ЮТЗапросыСлужебныйВызовСервера.РезультатЗапроса(ОписаниеЗапроса, Ложь); +#КонецЕсли + +КонецФункции + +// Определяет, есть ли в результате записи +// +// Параметры: +// ОписаниеЗапроса - см. ОписаниеЗапроса +// +// Возвращаемое значение: +// Булево - Результат пустой +Функция РезультатПустой(ОписаниеЗапроса) Экспорт + + Возврат ЮТЗапросыСлужебныйВызовСервера.РезультатПустой(ОписаниеЗапроса); + +КонецФункции + +// Описание простого запроса +// +// Возвращаемое значение: +// Структура - Описание запроса: +// * ИмяТаблицы - Строка - Имя таблицы, из которой нужно получить данные +// * ВыбираемыеПоля - Массив из Строка - Выражения выбираемых полей +// * КоличествоЗаписей - Число, Неопределено - Ограничение количества выбираемых записей +// * Условия - Массив из Строка - Коллекция выражений условий, которые будут объединены через `И` +// * ЗначенияПараметров - Структура - Набор параметров запроса +// * Порядок - Массив из Строка - Поля сортировки +Функция ОписаниеЗапроса() Экспорт + + Описание = Новый Структура(); + Описание.Вставить("ИмяТаблицы", ""); + Описание.Вставить("ВыбираемыеПоля", Новый Массив); + Описание.Вставить("КоличествоЗаписей", Неопределено); + Описание.Вставить("Условия", Новый Массив()); + Описание.Вставить("Порядок", Новый Массив()); + Описание.Вставить("ЗначенияПараметров", Новый Структура()); + + //@skip-check constructor-function-return-section + Возврат Описание; + +КонецФункции + +Функция НовыйОписаниеЗапроса(ИмяТаблицы, ПредикатыУсловия, ВыбираемыеПоля) Экспорт + + Возврат ЮТЗапросыСлужебныйКлиентСервер.ОписаниеЗапроса(ИмяТаблицы, ПредикатыУсловия, ВыбираемыеПоля); + +КонецФункции + +// Возвращает коллекцию движений документа +// +// Параметры: +// Документ - ДокументСсылка +// ИмяРегистра - Строка - Короткое или полное имя регистра движений +// +// Возвращаемое значение: +// Массив из Структура - Движения документа для клиента +// ТаблицаЗначений - Движения документа для сервера +Функция ДвиженияДокумента(Документ, Знач ИмяРегистра) Экспорт + + Если СтрНайти(ИмяРегистра, ".") = 0 Тогда + РегистрыДвижения = ЮТМетаданные.РегистрыДвиженийДокумента(Документ); + + Если НЕ РегистрыДвижения.Свойство(ИмяРегистра) Тогда + ВызватьИсключение "Документ не делает движений по регистру " + ИмяРегистра; + КонецЕсли; + + ИмяРегистра = РегистрыДвижения[ИмяРегистра]; + КонецЕсли; + + Предикат = ЮТест.Предикат().Реквизит("Регистратор").Равно(Документ); + ОписаниеЗапроса = ЮТЗапросыСлужебныйКлиентСервер.ОписаниеЗапроса(ИмяРегистра, Предикат, "*"); + ОписаниеЗапроса.Порядок.Добавить("НомерСтроки"); + + Возврат ЮТЗапросыСлужебныйВызовСервера.Записи(ОписаниеЗапроса, Ложь); + +КонецФункции + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТЗапросыСлужебныйВызовСервера.xml b/src/cfe/YAXUnit/CommonModules/ЮТЗапросыСлужебныйВызовСервера.xml new file mode 100644 index 0000000..48b0fd1 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТЗапросыСлужебныйВызовСервера.xml @@ -0,0 +1,23 @@ + + + + + ЮТЗапросыСлужебныйВызовСервера + + + ru + Запросы вызов сервера + + + + false + false + true + false + false + true + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТЗапросыСлужебныйВызовСервера/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТЗапросыСлужебныйВызовСервера/Ext/Module.bsl new file mode 100644 index 0000000..dc1e0ec --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТЗапросыСлужебныйВызовСервера/Ext/Module.bsl @@ -0,0 +1,397 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область СлужебныйПрограммныйИнтерфейс + +Функция РезультатЗапроса(Знач ОписаниеЗапроса, Знач ДляКлиента) Экспорт + + Запрос = Запрос(ОписаниеЗапроса); + РезультатЗапроса = Запрос.Выполнить(); + + Возврат ВыгрузитьРезультатЗапроса(РезультатЗапроса, ДляКлиента); + +КонецФункции + +// Результат пустой. +// +// Параметры: +// ОписаниеЗапроса - см. ЮТЗапросы.ОписаниеЗапроса +// +// Возвращаемое значение: +// Булево - Результат пустой +Функция РезультатПустой(Знач ОписаниеЗапроса) Экспорт + + Запрос = Запрос(ОписаниеЗапроса); + РезультатЗапроса = Запрос.Выполнить(); + + Возврат РезультатЗапроса.Пустой(); + +КонецФункции + +// Возвращает значения реквизитов ссылки +// +// Параметры: +// Ссылка - ЛюбаяСсылка +// ИменаРеквизитов - Строка +// ОдинРеквизит - Булево +// +// Возвращаемое значение: +// - Структура Из Произвольный - Значения реквизитов ссылки при получении значений множества реквизитов +// - Произвольный - Значение реквизита ссылки при получении значения одного реквизита +Функция ЗначенияРеквизитов(Знач Ссылка, Знач ИменаРеквизитов, Знач ОдинРеквизит) Экспорт + + ИмяТаблицы = Ссылка.Метаданные().ПолноеИмя(); + + ТекстЗапроса = СтрШаблон("ВЫБРАТЬ ПЕРВЫЕ 1 %1 ИЗ %2 ГДЕ Ссылка = &Ссылка", ИменаРеквизитов, ИмяТаблицы); + Запрос = Новый Запрос(ТекстЗапроса); + Запрос.УстановитьПараметр("Ссылка", Ссылка); + + Если ОдинРеквизит Тогда + Возврат ЗначениеИзЗапроса(Запрос, 0); + Иначе + Возврат ЗначенияИзЗапроса(Запрос, ИменаРеквизитов); + КонецЕсли; + +КонецФункции + +// Возвращяет записи результат запроса +// +// Параметры: +// ОписаниеЗапроса - см. ЮТЗапросы.ОписаниеЗапроса +// ОднаЗапись - Булево - Вернуть первую запись +// +// Возвращаемое значение: +// Массив из Структура, Структура, Неопределено - Записи +Функция Записи(Знач ОписаниеЗапроса, Знач ОднаЗапись) Экспорт + + Если ОднаЗапись Тогда + ОписаниеЗапроса.КоличествоЗаписей = 1; + КонецЕсли; + + Запрос = Запрос(ОписаниеЗапроса); + РезультатЗапроса = Запрос.Выполнить(); + + Записи = ВыгрузитьРезультатЗапроса(РезультатЗапроса, Истина); + + Если НЕ ОднаЗапись Тогда + Возврат Записи; + ИначеЕсли Записи.Количество() Тогда + Возврат Записи[0]; + Иначе + Возврат Неопределено; + КонецЕсли; + +КонецФункции + +// Возвращает значения реквизитов записи +// +// Параметры: +// ОписаниеЗапроса - см. ЮТЗапросы.ОписаниеЗапроса +// ОдинРеквизит - Булево +// +// Возвращаемое значение: +// - Структура Из Произвольный - Значения множества реквизитов записи +// - Произвольный - Значение одного реквизита записи +// +Функция ЗначенияРеквизитовЗаписи(Знач ОписаниеЗапроса, Знач ОдинРеквизит) Экспорт + + Запись = Записи(ОписаниеЗапроса, Истина); + + Если ТипЗнч(Запись) <> Тип("Структура") Тогда + Если ОдинРеквизит Тогда + Возврат Неопределено; + Иначе + Реквизиты = СтрСоединить(ПсевдонимыВыбираемыхПолей(ОписаниеЗапроса), ","); + Возврат Новый Структура(Реквизиты); + КонецЕсли; + КонецЕсли; + + Если ОдинРеквизит Тогда + Для Каждого КлючЗнач Из Запись Цикл + Возврат КлючЗнач.Значение; + КонецЦикла; + Иначе + Возврат Запись; + КонецЕсли; + +КонецФункции + +#КонецОбласти + +#Область СлужебныеПроцедурыИФункции + +// Запрос. +// +// Параметры: +// ОписаниеЗапроса - см. ЮТЗапросы.ОписаниеЗапроса +// +// Возвращаемое значение: +// Запрос +Функция Запрос(ОписаниеЗапроса) + + Запрос = Новый Запрос; + + Строки = Новый Массив(); + Строки.Добавить("ВЫБРАТЬ "); + + Если ОписаниеЗапроса.КоличествоЗаписей <> Неопределено Тогда + Строки.Добавить("ПЕРВЫЕ " + ЮТОбщий.ЧислоВСтроку(ОписаниеЗапроса.КоличествоЗаписей)); + КонецЕсли; + + Если ОписаниеЗапроса.ВыбираемыеПоля.Количество() Тогда + ВыбираемыеПоля = ОписаниеЗапроса.ВыбираемыеПоля; + Иначе + ВыбираемыеПоля = ЮТКоллекции.ЗначениеВМассиве("1 КАК Поле"); + КонецЕсли; + + Строки.Добавить(СтрСоединить(ВыбираемыеПоля, "," + Символы.ПС)); + Строки.Добавить("ИЗ " + ОписаниеЗапроса.ИмяТаблицы); + + Условия = СформироватьУсловия(ОписаниеЗапроса.Условия, ОписаниеЗапроса.ИмяТаблицы, Запрос); + + Если Условия.Количество() Тогда + Строки.Добавить("ГДЕ ("); + Строки.Добавить(СтрСоединить(Условия, ") И (" + Символы.ПС)); + Строки.Добавить(")"); + КонецЕсли; + + Если ОписаниеЗапроса.Порядок.Количество() Тогда + Строки.Добавить("УПОРЯДОЧИТЬ ПО "); + Строки.Добавить(СтрСоединить(ОписаниеЗапроса.Порядок, ",")); + КонецЕсли; + + Запрос.Текст = СтрСоединить(Строки, Символы.ПС); + ЮТКоллекции.ДополнитьСтруктуру(Запрос.Параметры, ОписаниеЗапроса.ЗначенияПараметров); + + Возврат Запрос; + +КонецФункции + +Функция ЗначенияИзЗапроса(Запрос, Реквизиты) + + Результат = Новый Структура(Реквизиты); + Выборка = Запрос.Выполнить().Выбрать(); + + Если Выборка.Следующий() Тогда + ЗаполнитьЗначенияСвойств(Результат, Выборка); + КонецЕсли; + + Возврат Результат; + +КонецФункции + +Функция ЗначениеИзЗапроса(Запрос, Реквизит) + + Выборка = Запрос.Выполнить().Выбрать(); + + Если Выборка.Следующий() Тогда + Возврат Выборка[Реквизит]; + Иначе + Возврат Неопределено; + КонецЕсли; + +КонецФункции + +Функция ВыгрузитьРезультатЗапроса(РезультатЗапроса, ВМассив) + + Если НЕ ВМассив Тогда + Возврат РезультатЗапроса.Выгрузить(); + Иначе + Результат = Новый Массив(); + КонецЕсли; + + Если РезультатЗапроса.Пустой() Тогда + Возврат Результат; + КонецЕсли; + + Реквизиты = Новый Массив(); + ТабличныеЧасти = Новый Массив(); + + ТипРезультатЗапроса = Тип("РезультатЗапроса"); + Для Каждого Колонка Из РезультатЗапроса.Колонки Цикл + + Реквизиты.Добавить(Колонка.Имя); + + Если Колонка.ТипЗначения.СодержитТип(ТипРезультатЗапроса) Тогда + ТабличныеЧасти.Добавить(Колонка.Имя); + КонецЕсли; + + КонецЦикла; + + ПараметрыКонструктора = СтрСоединить(Реквизиты, ","); + + Выборка = РезультатЗапроса.Выбрать(); + + Пока Выборка.Следующий() Цикл + + Запись = Новый Структура(ПараметрыКонструктора); + ЗаполнитьЗначенияСвойств(Запись, Выборка); + + Для Каждого ТабличнаяЧасть Из ТабличныеЧасти Цикл + Запись[ТабличнаяЧасть] = ВыгрузитьРезультатЗапроса(Выборка[ТабличнаяЧасть], ВМассив); + КонецЦикла; + + Результат.Добавить(Запись); + + КонецЦикла; + + Возврат Результат; + +КонецФункции + +Функция ПсевдонимыВыбираемыхПолей(ОписаниеЗапроса) + + Псевдонимы = Новый Массив; + + Запрос = Запрос(ОписаниеЗапроса); + + СхемаЗапроса = Новый СхемаЗапроса(); + СхемаЗапроса.УстановитьТекстЗапроса(Запрос.Текст); + + Для Каждого ЗапросСЗ Из СхемаЗапроса.ПакетЗапросов Цикл + Для Каждого КолонкаСЗ Из ЗапросСЗ.Колонки Цикл + Псевдонимы.Добавить(КолонкаСЗ.Псевдоним); + КонецЦикла; + КонецЦикла; + + Возврат Псевдонимы; + +КонецФункции + +Функция ШаблонУсловия(ВыражениеПредиката, ВыраженияПредикатов, ТипРеквизита) + Выражение = ВыражениеПредиката.ВидСравнения; + + Отрицание = ЮТПредикатыСлужебныйКлиентСервер.ЭтоВыраженияОтрицания(Выражение); + Если Отрицание Тогда + Выражение = ЮТПредикатыСлужебныйКлиентСервер.ВыраженияБезОтрицания(Выражение); + КонецЕсли; + + Если Выражение = ВыраженияПредикатов.Равно Тогда + Если ЭтоСтрокаНеограниченнойДлинны(ТипРеквизита) Тогда + Шаблон = СтрШаблон("ВЫРАЗИТЬ(%%1 КАК Строка(%1)) = &%%2", XMLСтрока(СтрДлина(ВыражениеПредиката.Значение) + 1)); + Иначе + Шаблон = "%1 = &%2"; + КонецЕсли; + ИначеЕсли Выражение = ВыраженияПредикатов.Больше Тогда + Шаблон = "%1 > &%2"; + ИначеЕсли Выражение = ВыраженияПредикатов.БольшеРавно Тогда + Шаблон = "%1 >= &%2"; + ИначеЕсли Выражение = ВыраженияПредикатов.Меньше Тогда + Шаблон = "%1 < &%2"; + ИначеЕсли Выражение = ВыраженияПредикатов.МеньшеРавно Тогда + Шаблон = "%1 <= &%2"; + ИначеЕсли Выражение = ВыраженияПредикатов.ИмеетТип Тогда + Шаблон = "ТИПЗНАЧЕНИЯ(%1) = &%2"; + ИначеЕсли Выражение = ВыраженияПредикатов.Содержит Тогда + Шаблон = "%1 ПОДОБНО ""%%"" + &%2 + ""%%"""; + ИначеЕсли Выражение = ВыраженияПредикатов.ВСписке Тогда + Шаблон = "%1 В (&%2)"; + ИначеЕсли Выражение = ВыраженияПредикатов.Заполнено Тогда + // TODO Реализовать + ВызватьИсключение "Проверка заполненности пока не поддерживается"; + Иначе + ВызватьИсключение "Неподдерживаемое выражения предикатов " + Выражение; + КонецЕсли; + + Если Отрицание Тогда + Шаблон = СтрШаблон("НЕ (%1)", Шаблон); + КонецЕсли; + + Возврат Шаблон; + +КонецФункции + +Функция ТипыРеквизитов(ИмяТаблицы, Предикаты) + + Результат = Новый Соответствие(); + Реквизиты = Новый Массив(); + + ПсевдонимТаблицы = ЮТТестовыеДанные.СлучайныйИдентификатор() + СтрЗаменить(ИмяТаблицы, ".", ""); + ДлинаПсевдонима = СтрДлина(ПсевдонимТаблицы); + + Для Каждого ВыражениеПредиката Из Предикаты Цикл + Если ЮТПредикатыСлужебныйКлиентСервер.ЭтоПредикат(ВыражениеПредиката) И ЗначениеЗаполнено(ВыражениеПредиката.ИмяРеквизита) Тогда + Реквизиты.Добавить(СтрШаблон("%1.%2 КАК _%3", ПсевдонимТаблицы, ВыражениеПредиката.ИмяРеквизита, Реквизиты.Количество())); + КонецЕсли; + КонецЦикла; + + Если НЕ ЗначениеЗаполнено(Реквизиты) Тогда + Возврат Результат; + КонецЕсли; + + Схема = Новый СхемаЗапроса(); + + Попытка + Схема.УстановитьТекстЗапроса(СтрШаблон("ВЫБРАТЬ %1 ИЗ %2 КАК %3", СтрСоединить(Реквизиты, ","), ИмяТаблицы, ПсевдонимТаблицы)); + Исключение + ЮТРегистрацияОшибок.ДобавитьПояснениеОшибки("Не удалось получить типы реквизитов отбора. + |Возможно имена реквизитов заданы неверно"); + ВызватьИсключение; + КонецПопытки; + + Для Каждого Колонка Из Схема.ПакетЗапросов[0].Колонки Цикл + Выражение = Строка(Колонка.Поля[0]); + Результат.Вставить(Сред(Выражение, ДлинаПсевдонима + 2), Новый ОписаниеТипов(Колонка.ТипЗначения, , "Null")); + КонецЦикла; + + Возврат Результат; + +КонецФункции + +Функция ЭтоСтрокаНеограниченнойДлинны(ТипРеквизита) + + Возврат ТипРеквизита <> Неопределено + И ТипРеквизита.СодержитТип(Тип("Строка")) + И ТипРеквизита.КвалификаторыСтроки.Длина = 0; + +КонецФункции + +Функция СформироватьУсловия(Условия, ИмяТаблицы, Запрос) Экспорт + + Результат = Новый Массив(); + + Если НЕ ЗначениеЗаполнено(Условия) Тогда + Возврат Результат; + КонецЕсли; + + ТипыРеквизитов = ТипыРеквизитов(ИмяТаблицы, Условия); + ВидыСравнения = ЮТПредикаты.Выражения(); + + Для Каждого Условие Из Условия Цикл + + Если НЕ ЮТПредикатыСлужебныйКлиентСервер.ЭтоПредикат(Условие) Тогда + Результат.Добавить(Условие); + Продолжить; + КонецЕсли; + + ИмяПараметра = "Параметр_" + ЮТОбщий.ЧислоВСтроку(Запрос.Параметры.Количество() + 1); + ТипРеквизита = ТипыРеквизитов[Условие.ИмяРеквизита]; + Шаблон = ШаблонУсловия(Условие, ВидыСравнения, ТипРеквизита); + + ТекстУсловия = СтрШаблон(Шаблон, Условие.ИмяРеквизита, ИмяПараметра); + + Результат.Добавить(ТекстУсловия); + Запрос.Параметры.Вставить(ИмяПараметра, Условие.Значение); + + КонецЦикла; + + Возврат Результат; + +КонецФункции + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТЗапросыСлужебныйКлиентСервер.xml b/src/cfe/YAXUnit/CommonModules/ЮТЗапросыСлужебныйКлиентСервер.xml new file mode 100644 index 0000000..831a9a1 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТЗапросыСлужебныйКлиентСервер.xml @@ -0,0 +1,23 @@ + + + + + ЮТЗапросыСлужебныйКлиентСервер + + + ru + Запросы клиент сервер + + + + false + true + true + false + true + false + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТЗапросыСлужебныйКлиентСервер/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТЗапросыСлужебныйКлиентСервер/Ext/Module.bsl new file mode 100644 index 0000000..42f7360 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТЗапросыСлужебныйКлиентСервер/Ext/Module.bsl @@ -0,0 +1,71 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область СлужебныйПрограммныйИнтерфейс + +Функция ОписаниеЗапроса(ИмяТаблицы, ПредикатыУсловия, ВыбираемыеПоля = Неопределено) Экспорт + + Описание = ЮТЗапросы.ОписаниеЗапроса(); + Описание.ИмяТаблицы = ИмяТаблицы; + Если ВыбираемыеПоля = Неопределено Тогда + Описание.ВыбираемыеПоля.Добавить("1 КАК Проверка"); + Иначе + ЗаполнитьВыбираемыеПоля(Описание, ВыбираемыеПоля); + КонецЕсли; + + Если ПредикатыУсловия <> Неопределено Тогда + Описание.Условия = ЮТПредикатыСлужебныйКлиентСервер.НаборПредикатов(ПредикатыУсловия); + КонецЕсли; + + Возврат Описание; + +КонецФункции + +#КонецОбласти + +#Область СлужебныеПроцедурыИФункции + +Процедура ЗаполнитьВыбираемыеПоля(ОписаниеЗапроса, Знач ВыбираемыеПоля) + + ТипПараметра = ТипЗнч(ВыбираемыеПоля); + + Если ТипПараметра = Тип("Строка") Тогда + ВыбираемыеПоля = ЮТСтроки.РазделитьСтроку(ВыбираемыеПоля, ","); + ТипПараметра = Тип("Массив"); + КонецЕсли; + + Если ТипПараметра = Тип("Массив") Тогда + + ОписаниеЗапроса.ВыбираемыеПоля = ВыбираемыеПоля; + + ИначеЕсли ТипПараметра = Тип("Структура") Тогда + + Для Каждого Поле Из ВыбираемыеПоля Цикл + Выражение = СтрШаблон("%1 КАК %2", Поле.Значение, Поле.Ключ); + ОписаниеЗапроса.ВыбираемыеПоля.Добавить(Выражение); + КонецЦикла; + + Иначе + + ВызватьИсключение ЮТИсключения.НеподдерживаемыйПараметрМетода("ЮТЗапросыКлиентСервер.ЗаполнитьВыбираемыеПоля", ВыбираемыеПоля); + + КонецЕсли; + +КонецПроцедуры + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТИсключения.xml b/src/cfe/YAXUnit/CommonModules/ЮТИсключения.xml new file mode 100644 index 0000000..592a9aa --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТИсключения.xml @@ -0,0 +1,23 @@ + + + + + ЮТИсключения + + + ru + Исключения + + + + false + true + true + false + true + false + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТИсключения/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТИсключения/Ext/Module.bsl new file mode 100644 index 0000000..58f1621 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТИсключения/Ext/Module.bsl @@ -0,0 +1,64 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область ПрограммныйИнтерфейс + +// Формирует текст исключения о некорректных параметрах вызова метода +// +// Параметры: +// ИмяМетода - Строка +// Пояснение - Строка +// +// Возвращаемое значение: +// Строка - Текст исключения +Функция НекорректныеПараметрыМетода(ИмяМетода, Пояснение = Неопределено) Экспорт + + Сообщение = СтрШаблон("Некорректные параметры метода `%1`"); + Возврат ЮТСтроки.ДобавитьСтроку(Сообщение, Пояснение, ", "); + +КонецФункции + +// Формирует текст исключения о неподдерживаемом значении параметра вызова метода +// +// Параметры: +// ИмяМетода - Строка +// ЗначениеПараметра - Произвольный +// +// Возвращаемое значение: +// Строка - Текст исключения +Функция НеподдерживаемыйПараметрМетода(ИмяМетода, ЗначениеПараметра) Экспорт + + Возврат СтрШаблон("Неподдерживаемый параметр метода `%1` `%2`(%3)", ИмяМетода, ЗначениеПараметра, ТипЗнч(ЗначениеПараметра)); + +КонецФункции + +// Формирует текст исключения о недоступности метода в указанном контексте +// +// Параметры: +// ИмяМетода - Строка +// ИмяКонтекста - Строка +// +// Возвращаемое значение: +// Строка - Текст исключения +Функция МетодНеДоступен(ИмяМетода, ИмяКонтекста = "веб-клиенте") Экспорт + + Возврат СтрШаблон("Метод `%1` не доступен в/на %2", ИмяМетода, ИмяКонтекста); + +КонецФункции + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТИсполнительСлужебныйВызовСервера.xml b/src/cfe/YAXUnit/CommonModules/ЮТИсполнительСлужебныйВызовСервера.xml new file mode 100644 index 0000000..0ea2d97 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТИсполнительСлужебныйВызовСервера.xml @@ -0,0 +1,23 @@ + + + + + ЮТИсполнительСлужебныйВызовСервера + + + ru + Исполнитель тестов (сервер) + + + + false + false + true + false + false + true + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТИсполнительСлужебныйВызовСервера/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТИсполнительСлужебныйВызовСервера/Ext/Module.bsl new file mode 100644 index 0000000..2784093 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТИсполнительСлужебныйВызовСервера/Ext/Module.bsl @@ -0,0 +1,36 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область СлужебныйПрограммныйИнтерфейс + +// ПрогонНаборов +// Выполняет тесты наборов модуля. Возвращает результат прогона +// Это обертка для прогона на сервере +// Параметры: +// Наборы - Массив из см. ЮТФабрикаСлужебный.ОписаниеИсполняемогоНабораТестов - Наборы исполняемых тестов, структуру набора см. ЮТФабрикаСлужебный.ОписаниеИсполняемогоНабораТестов +// ТестовыйМодуль - см. ЮТФабрикаСлужебный.ОписаниеТестовогоМодуля +// +// Возвращаемое значение: +// Массив из см. ЮТФабрикаСлужебный.ОписаниеИсполняемогоНабораТестов - Результат прогона наборов тестов, структура набора см. ЮТФабрикаСлужебный.ОписаниеИсполняемогоНабораТестов +Функция ВыполнитьГруппуНаборовТестов(Знач Наборы, Знач ТестовыйМодуль) Экспорт + + Возврат ЮТИсполнительСлужебныйКлиентСервер.ВыполнитьГруппуНаборовТестов(Наборы, ТестовыйМодуль); + +КонецФункции + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТИсполнительСлужебныйГлобальный.xml b/src/cfe/YAXUnit/CommonModules/ЮТИсполнительСлужебныйГлобальный.xml new file mode 100644 index 0000000..3723f56 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТИсполнительСлужебныйГлобальный.xml @@ -0,0 +1,23 @@ + + + + + ЮТИсполнительСлужебныйГлобальный + + + ru + Исполнитель глобальный + + + + true + true + false + false + true + false + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТИсполнительСлужебныйГлобальный/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТИсполнительСлужебныйГлобальный/Ext/Module.bsl new file mode 100644 index 0000000..366aba7 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТИсполнительСлужебныйГлобальный/Ext/Module.bsl @@ -0,0 +1,27 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область СлужебныйПрограммныйИнтерфейс + +Процедура ЮТВыполнитьМодульноеТестирование() Экспорт + + ЮТИсполнительСлужебныйКлиент.ВыполнитьМодульноеТестирование(); + +КонецПроцедуры + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТИсполнительСлужебныйКлиент.xml b/src/cfe/YAXUnit/CommonModules/ЮТИсполнительСлужебныйКлиент.xml new file mode 100644 index 0000000..5e0ee0f --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТИсполнительСлужебныйКлиент.xml @@ -0,0 +1,23 @@ + + + + + ЮТИсполнительСлужебныйКлиент + + + ru + Исполнитель клиент + + + + false + true + false + false + true + false + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТИсполнительСлужебныйКлиент/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТИсполнительСлужебныйКлиент/Ext/Module.bsl new file mode 100644 index 0000000..25dd1f1 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТИсполнительСлужебныйКлиент/Ext/Module.bsl @@ -0,0 +1,461 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область СлужебныйПрограммныйИнтерфейс + +Процедура ВыполнитьМодульноеТестирование() Экспорт + + ПараметрыИсполнения = ПараметрыИсполнения(); + ПараметрыИсполнения.АргументыЗапуска = ПараметрЗапуска; + + ДобавитьОбработчикЦепочки(ПараметрыИсполнения, "ОбработчикЗагрузитьПараметры"); + ДобавитьОбработчикЦепочки(ПараметрыИсполнения, "ОбработчикАнализПараметровЗапуска"); + ДобавитьОбработчикЦепочки(ПараметрыИсполнения, "ОбработчикПодключитьКомпоненты"); + ДобавитьОбработчикЦепочки(ПараметрыИсполнения, "ОбработчикИнициализация"); + ДобавитьОбработчикЦепочки(ПараметрыИсполнения, "ОбработчикЗагрузитьТесты"); + ДобавитьОбработчикЦепочки(ПараметрыИсполнения, "ОбработчикВыполнитьТестирование"); + ДобавитьОбработчикЦепочки(ПараметрыИсполнения, "ОбработчикСохранитьОтчет"); + ДобавитьОбработчикЦепочки(ПараметрыИсполнения, "ОбработчикСохранитьКодВозврата"); + ДобавитьОбработчикЦепочки(ПараметрыИсполнения, "ОбработчикЗавершить"); + + ЮТАсинхроннаяОбработкаСлужебныйКлиент.ВызватьСледующийОбработчик(ПараметрыИсполнения); + +КонецПроцедуры + +Процедура ВыполнитьМодульноеТестированиеПоНастройке(ПараметрыЗапуска, ОбработчикЗавершения) Экспорт + + ПараметрыИсполнения = ПараметрыИсполнения(); + ПараметрыИсполнения.ПараметрыЗапуска = ПараметрыЗапуска; + + ДобавитьОбработчикЦепочки(ПараметрыИсполнения, "ОбработчикИнициализация"); + ДобавитьОбработчикЦепочки(ПараметрыИсполнения, "ОбработчикЗагрузитьТесты"); + ДобавитьОбработчикЦепочки(ПараметрыИсполнения, "ОбработчикВыполнитьТестирование"); + ПараметрыИсполнения.Цепочка.Добавить(ОбработчикЗавершения); + + ЮТАсинхроннаяОбработкаСлужебныйКлиент.ВызватьСледующийОбработчик(ПараметрыИсполнения); + +КонецПроцедуры + +Функция ПараметрыИсполнения() Экспорт + + Параметры = ЮТАсинхроннаяОбработкаСлужебныйКлиент.ЦепочкаАсинхроннойОбработки(); + Параметры.Вставить("АргументыЗапуска"); + Параметры.Вставить("ПараметрыЗапуска"); + Параметры.Вставить("ИсполняемыеТестовыеМодули"); + Параметры.Вставить("РезультатыТестирования"); + + Возврат Параметры; + +КонецФункции + +Функция ВыполнитьТестыМодуля(ТестовыйМодуль) Экспорт + + Результаты = Новый Массив(); + + КонтекстыИсполнения = ЮТФабрика.КонтекстыИсполнения(); + + КлиентскиеНаборы = Новый Массив(); + СерверныеНаборы = Новый Массив(); + ПропущенныеНаборы = Новый Массив(); + + Для Каждого Набор Из ТестовыйМодуль.НаборыТестов Цикл + + Если НЕ Набор.Выполнять Тогда + ПропущенныеНаборы.Добавить(Набор); + Продолжить; + КонецЕсли; + + РежимИсполнения = ЮТФабрикаСлужебный.КонтекстИсполнения(Набор.Режим); + + Если РежимИсполнения = КонтекстыИсполнения.Клиент Тогда + КлиентскиеНаборы.Добавить(Набор); + ИначеЕсли РежимИсполнения = КонтекстыИсполнения.Сервер Тогда + СерверныеНаборы.Добавить(Набор); + Иначе + ПропущенныеНаборы.Добавить(Набор); + КонецЕсли; + + КонецЦикла; + + ТестовыйМодульОблегченный = ЮТКоллекции.СкопироватьСтруктуру(ТестовыйМодуль); + ТестовыйМодульОблегченный.НаборыТестов = Новый Массив(); + + Если ЗначениеЗаполнено(КлиентскиеНаборы) Тогда + Результаты = ЮТИсполнительСлужебныйКлиентСервер.ВыполнитьГруппуНаборовТестов(КлиентскиеНаборы, ТестовыйМодульОблегченный); + КонецЕсли; + + Если ЗначениеЗаполнено(СерверныеНаборы) Тогда + Результат = ЮТИсполнительСлужебныйВызовСервера.ВыполнитьГруппуНаборовТестов(СерверныеНаборы, ТестовыйМодульОблегченный); + ЮТЛогированиеСлужебный.ВывестиСерверныеСообщения(); + ЮТКоллекции.ДополнитьМассив(Результаты, Результат); + КонецЕсли; + + ЮТКоллекции.ДополнитьМассив(Результаты, ПропущенныеНаборы); + + ТестовыйМодульОблегченный.НаборыТестов = Результаты; + + Возврат ТестовыйМодульОблегченный; + +КонецФункции + +Процедура ОбработкаОшибки(ТекстОшибки) Экспорт + ВызватьИсключение ТекстОшибки; +КонецПроцедуры + +Процедура ВыполнитьИнициализацию(ПараметрыЗапуска) Экспорт + + ЮТКонтекстСлужебный.ИнициализироватьКонтекст(); + ЮТКонтекстСлужебный.УстановитьГлобальныеНастройкиВыполнения(ПараметрыЗапуска.settings); + // Повторно сохраним для передачи на сервер + ЮТКонтекстСлужебный.УстановитьГлобальныеНастройкиВыполнения(ЮТКонтекстСлужебный.ГлобальныеНастройкиВыполнения()); + + ЮТСобытияСлужебный.Инициализация(ПараметрыЗапуска); + +КонецПроцедуры + +#КонецОбласти + +#Область СлужебныеПроцедурыИФункции + +#Область ОбработчикиЦепочкиДействий + +Процедура ОбработчикОшибки(ИнформацияОбОшибке, СтандартнаяОбработка, ДополнительныеПараметры) Экспорт + + // TODO Подумать надо ли и как реализовать нормально + +КонецПроцедуры + +Процедура ОбработчикЗагрузитьПараметры(Результат, ДополнительныеПараметры) Экспорт + + Обработчик = ЮТАсинхроннаяОбработкаСлужебныйКлиент.СледующийОбработчик(ДополнительныеПараметры); + ЮТПараметрыЗапускаСлужебный.ПараметрыЗапуска(ДополнительныеПараметры.АргументыЗапуска, Обработчик); + +КонецПроцедуры + +Процедура ОбработчикАнализПараметровЗапуска(ПараметрыЗапуска, ДополнительныеПараметры) Экспорт + + ДополнительныеПараметры.ПараметрыЗапуска = ПараметрыЗапуска; + + Если НЕ ПараметрыЗапуска.ВыполнятьМодульноеТестирование Тогда + Возврат; + КонецЕсли; + + ЮТАсинхроннаяОбработкаСлужебныйКлиент.ВызватьСледующийОбработчик(ДополнительныеПараметры); + +КонецПроцедуры + +Процедура ОбработчикИнициализация(Результат, ДополнительныеПараметры) Экспорт + + ВыполнитьИнициализацию(ДополнительныеПараметры.ПараметрыЗапуска); + ЮТАсинхроннаяОбработкаСлужебныйКлиент.ВызватьСледующийОбработчик(ДополнительныеПараметры); + +КонецПроцедуры + +Процедура ОбработчикЗагрузитьТесты(Результат, ДополнительныеПараметры) Экспорт + + ЮТСобытияСлужебный.ПередЧтениеСценариев(); + + ТестовыеМодули = ЮТЧитательСлужебный.ЗагрузитьТесты(ДополнительныеПараметры.ПараметрыЗапуска); + ЮТСобытияСлужебный.ПослеЧтенияСценариев(ТестовыеМодули); + + ИсполняемыеТестовыеМодули = Новый Массив(); + + Для Каждого ТестовыйМодуль Из ТестовыеМодули Цикл + ИсполняемыйТестовыйМодуль = ИсполняемыйТестовыйМодуль(ТестовыйМодуль); + ИсполняемыеТестовыеМодули.Добавить(ИсполняемыйТестовыйМодуль); + КонецЦикла; + + ЮТСобытияСлужебный.ПослеФормированияИсполняемыхНаборовТестов(ИсполняемыеТестовыеМодули); + ДополнительныеПараметры.ИсполняемыеТестовыеМодули = ИсполняемыеТестовыеМодули; + + ЮТАсинхроннаяОбработкаСлужебныйКлиент.ВызватьСледующийОбработчик(ДополнительныеПараметры, ИсполняемыеТестовыеМодули); + +КонецПроцедуры + +Процедура ОбработчикВыполнитьТестирование(Результат, ДополнительныеПараметры) Экспорт + + ЮТСобытияСлужебный.ПередВыполнениемТестов(ДополнительныеПараметры.ИсполняемыеТестовыеМодули); + + РезультатыТестирования = Новый Массив(); + + Для Каждого ТестовыйМодуль Из ДополнительныеПараметры.ИсполняемыеТестовыеМодули Цикл + + РезультатыПрогонаМодуля = ВыполнитьТестыМодуля(ТестовыйМодуль); + РезультатыТестирования.Добавить(РезультатыПрогонаМодуля); + + КонецЦикла; + + ЮТСобытияСлужебный.ПослеВыполненияТестов(РезультатыТестирования); + + ДополнительныеПараметры.РезультатыТестирования = РезультатыТестирования; + ЮТАсинхроннаяОбработкаСлужебныйКлиент.ВызватьСледующийОбработчик(ДополнительныеПараметры, РезультатыТестирования); + +КонецПроцедуры + +Процедура ОбработчикСохранитьОтчет(Результат, ДополнительныеПараметры) Экспорт + + Если ЗначениеЗаполнено(ДополнительныеПараметры.ПараметрыЗапуска.reportPath) Тогда + Обработчик = ЮТАсинхроннаяОбработкаСлужебныйКлиент.СледующийОбработчик(ДополнительныеПараметры); + ЮТОтчетСлужебный.СформироватьОтчет(ДополнительныеПараметры.РезультатыТестирования, ДополнительныеПараметры.ПараметрыЗапуска, Обработчик); + Иначе + ЮТАсинхроннаяОбработкаСлужебныйКлиент.ВызватьСледующийОбработчик(ДополнительныеПараметры); + КонецЕсли; + +КонецПроцедуры + +Процедура ОбработчикСохранитьКодВозврата(Результат, ДополнительныеПараметры) Экспорт + + ЗаписатьКодВозврата(ДополнительныеПараметры.РезультатыТестирования, ДополнительныеПараметры.ПараметрыЗапуска); + ЮТАсинхроннаяОбработкаСлужебныйКлиент.ВызватьСледующийОбработчик(ДополнительныеПараметры); + +КонецПроцедуры + +Процедура ОбработчикЗавершить(Результат, ДополнительныеПараметры) Экспорт + + Параметры = ДополнительныеПараметры.ПараметрыЗапуска; + ЮТКонтекстСлужебный.УдалитьКонтекст(); + + Если Параметры.showReport Тогда + ПоказатьОтчет(ДополнительныеПараметры.РезультатыТестирования, Параметры); + ИначеЕсли Параметры.CloseAfterTests Тогда + ПрекратитьРаботуСистемы(Ложь); + КонецЕсли; + +КонецПроцедуры + +Процедура ОбработчикПодключитьКомпоненты(Результат, ДополнительныеПараметры) Экспорт + + Если ДополнительныеПараметры.ПараметрыЗапуска.ПодключатьВнешниеКомпоненты Тогда + Обработчик = ЮТАсинхроннаяОбработкаСлужебныйКлиент.СледующийОбработчик(ДополнительныеПараметры); + ЮТКомпонентыСлужебныйКлиент.ТихаяУстановкаКомпонент(Обработчик); + Иначе + ЮТАсинхроннаяОбработкаСлужебныйКлиент.ВызватьСледующийОбработчик(ДополнительныеПараметры); + КонецЕсли; + +КонецПроцедуры + +#КонецОбласти + +#Область ОбработчикиСобытий + +Процедура ПередВыполнениемТестов(ИсполняемыеМодули) Экспорт + + ЮТКонтекстСлужебный.УстановитьКонтекстИсполнения(ЮТФабрикаСлужебный.НовыйКонтекстИсполнения()); + +КонецПроцедуры + +#КонецОбласти + +Процедура ДобавитьОбработчикЦепочки(ПараметрыИсполнения, ИмяМетода) + + Обработчик = Новый ОписаниеОповещения(ИмяМетода, ЭтотОбъект, ПараметрыИсполнения, "ОбработчикОшибки", ЭтотОбъект); + ПараметрыИсполнения.Цепочка.Добавить(Обработчик); + +КонецПроцедуры + +Функция ИсполняемыйТестовыйМодуль(ТестовыйМодуль) + + ИсполняемыйТестовыйМодуль = ЮТФабрикаСлужебный.ОписаниеИсполняемогоТестовогоМодуля(ТестовыйМодуль); + + КонтекстыПриложения = ЮТФабрикаСлужебный.КонтекстыПриложения(); + КонтекстыМодуля = ЮТФабрикаСлужебный.КонтекстыМодуля(ТестовыйМодуль.МетаданныеМодуля); + КонтекстыИсполнения = ЮТФабрика.КонтекстыИсполнения(); + + ИсполняемыйТестовыйМодуль.НаборыТестов = ИсполняемыеНаборыМодуля(ТестовыйМодуль); + + Для Каждого Набор Из ИсполняемыйТестовыйМодуль.НаборыТестов Цикл + + КонтекстИсполнения = ЮТФабрикаСлужебный.КонтекстИсполнения(Набор.Режим); + + Если КонтекстыПриложения.Найти(Набор.Режим) = Неопределено Тогда + ОшибкаКонтекста = "Неподдерживаемый режим запуска"; + ИначеЕсли КонтекстыМодуля.Найти(Набор.Режим) = Неопределено Тогда + ОшибкаКонтекста = "Модуль не доступен в этом контексте"; + ИначеЕсли КонтекстИсполнения <> КонтекстыИсполнения.Сервер И КонтекстИсполнения <> КонтекстыИсполнения.Клиент Тогда + ОшибкаКонтекста = "Неизвестный контекст/режим исполнения"; + Иначе + ОшибкаКонтекста = Неопределено; + КонецЕсли; + + Если ОшибкаКонтекста <> Неопределено Тогда + Набор.Выполнять = Ложь; + ЮТРегистрацияОшибокСлужебный.ЗарегистрироватьОшибкуРежимаВыполнения(Набор, ОшибкаКонтекста); + Для Каждого Тест Из Набор.Тесты Цикл + ЮТРегистрацияОшибокСлужебный.ЗарегистрироватьОшибкуРежимаВыполнения(Тест, ОшибкаКонтекста); + КонецЦикла; + КонецЕсли; + + КонецЦикла; + + Возврат ИсполняемыйТестовыйМодуль; + +КонецФункции + +Функция ИсполняемыеНаборыМодуля(ТестовыйМодуль) + + Результат = Новый Массив(); + + Для Каждого ТестовыйНабор Из ТестовыйМодуль.НаборыТестов Цикл + + НаборыКонтекстов = Новый Структура; + + ТестыНабора = ЮТКоллекции.ЗначениеСтруктуры(ТестовыйНабор, "Тесты", Новый Массив()); + ОбработатьОшибкиЧтенияНабора(ТестовыйНабор, ТестовыйМодуль); + + Для Каждого Тест Из ТестыНабора Цикл + + Для Каждого Контекст Из Тест.КонтекстВызова Цикл + + Если НЕ НаборыКонтекстов.Свойство(Контекст) Тогда + ИсполняемыйНабор = ЮТФабрикаСлужебный.ОписаниеИсполняемогоНабораТестов(ТестовыйНабор, ТестовыйМодуль); + ИсполняемыйНабор.Режим = Контекст; + НаборыКонтекстов.Вставить(Контекст, ИсполняемыйНабор); + Иначе + ИсполняемыйНабор = НаборыКонтекстов[Контекст]; + КонецЕсли; + + ИсполняемыйТест = ЮТФабрикаСлужебный.ОписаниеИсполняемогоТеста(Тест, Контекст, ТестовыйМодуль); + Если Тест.Свойство("Ошибки") И Тест.Ошибки.Количество() > 0 Тогда + ИсполняемыйТест.Ошибки = ЮТКоллекции.СкопироватьМассив(Тест.Ошибки); + КонецЕсли; + ИсполняемыйНабор.Тесты.Добавить(ИсполняемыйТест); + + КонецЦикла; + + КонецЦикла; + + Если НаборыКонтекстов.Количество() Тогда + + Для Каждого Элемент Из НаборыКонтекстов Цикл + Результат.Добавить(Элемент.Значение); + КонецЦикла; + + КонецЕсли; + + КонецЦикла; + + Возврат Результат; + +КонецФункции + +Процедура ОбработатьОшибкиЧтенияНабора(Набор, Модуль) + ТестыНабора = ЮТКоллекции.ЗначениеСтруктуры(Набор, "Тесты", Новый Массив()); + Ошибки = ЮТКоллекции.ЗначениеСтруктуры(Набор, "Ошибки", Новый Массив()); + + Если Ошибки.Количество() > 0 Тогда + Для Каждого Ошибка Из Ошибки Цикл + Если Ошибка.ТипОшибки = ЮТФабрикаСлужебный.ТипыОшибок().ЧтенияТестов Тогда + Тест = ОписаниеТестаСОшибкойЧтения(Модуль, Ошибка); + ТестыНабора.Добавить(Тест); + + Прервать; + КонецЕсли; + КонецЦикла; + КонецЕсли; +КонецПроцедуры + +Функция ОписаниеТестаСОшибкойЧтения(Модуль, Ошибка) + Контексты = ЮТФабрикаСлужебный.КонтекстыМодуля(Модуль.МетаданныеМодуля); + Тест = ЮТФабрикаСлужебный.ОписаниеТеста("ИсполняемыеСценарии", "ИсполняемыеСценарии", Контексты); + Тест.Вставить("Ошибки", Новый Массив); + Тест.Ошибки.Добавить(ЮТКоллекции.СкопироватьСтруктуру(Ошибка)); + + Возврат Тест; +КонецФункции + +Процедура ПоказатьОтчет(РезультатыТестирования, Параметры) + + Данные = Новый Структура("РезультатыТестирования, ПараметрыЗапуска", РезультатыТестирования, Параметры); + АдресДанных = ПоместитьВоВременноеХранилище(Данные, Новый УникальныйИдентификатор()); + + ОткрытьФорму("Обработка.ЮТЮнитТесты.Форма.Основная", Новый Структура("АдресХранилища", АдресДанных)); + +КонецПроцедуры + +// Записать код возврата. +// +// Параметры: +// РезультатыТестирования - Массив из см. ЮТФабрикаСлужебный.ОписаниеИсполняемогоТестовогоМодуля +// Параметры - см. ЮТФабрика.ПараметрыЗапуска +Процедура ЗаписатьКодВозврата(РезультатыТестирования, Параметры) + + Успешно = Истина; + + Если ПустаяСтрока(Параметры.exitCode) Тогда + Возврат; + КонецЕсли; + + Для Каждого Модуль Из РезультатыТестирования Цикл + + Для Каждого Набор Из Модуль.НаборыТестов Цикл + + Если РезультатТестаСодержитОшибки(Набор) Тогда + Успешно = Ложь; + Прервать; + КонецЕсли; + + Для Каждого Тест Из Набор.Тесты Цикл + + Если РезультатТестаСодержитОшибки(Тест) Тогда + Успешно = Ложь; + Прервать; + КонецЕсли; + + КонецЦикла; + + Если НЕ Успешно Тогда + Прервать; + КонецЕсли; + + КонецЦикла; + + Если НЕ Успешно Тогда + Прервать; + КонецЕсли; + + КонецЦикла; + +#Если ВебКлиент Тогда + ВызватьИсключение ЮТИсключения.МетодНеДоступен("ЮТИсполнительКлиент.ЗаписатьКодВозврата"); +#Иначе + Запись = Новый ЗаписьТекста(Параметры.exitCode, КодировкаТекста.UTF8); + Запись.ЗаписатьСтроку(?(Успешно, 0, 1)); + Запись.Закрыть(); +#КонецЕсли + +КонецПроцедуры + +Функция РезультатТестаСодержитОшибки(Тест) + Результат = Ложь; + + Если НЕ ЗначениеЗаполнено(Тест.Ошибки) Тогда + Возврат Результат; + КонецЕсли; + + ТипОшибкиПропущен = ЮТФабрикаСлужебный.ТипыОшибок().Пропущен; + Для Каждого ОписаниеОшибки Из Тест.Ошибки Цикл + Если ОписаниеОшибки.ТипОшибки <> ТипОшибкиПропущен Тогда + Результат = Истина; + Прервать; + КонецЕсли; + КонецЦикла; + + Возврат Результат; +КонецФункции + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТИсполнительСлужебныйКлиентСервер.xml b/src/cfe/YAXUnit/CommonModules/ЮТИсполнительСлужебныйКлиентСервер.xml new file mode 100644 index 0000000..d2a94fd --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТИсполнительСлужебныйКлиентСервер.xml @@ -0,0 +1,23 @@ + + + + + ЮТИсполнительСлужебныйКлиентСервер + + + ru + Исполнитель тестов + + + + false + true + true + false + true + false + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТИсполнительСлужебныйКлиентСервер/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТИсполнительСлужебныйКлиентСервер/Ext/Module.bsl new file mode 100644 index 0000000..77a0bf1 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТИсполнительСлужебныйКлиентСервер/Ext/Module.bsl @@ -0,0 +1,185 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область СлужебныйПрограммныйИнтерфейс + +// Выполняет тесты группы наборов, соответствующих одному режиму выполнения (клиент/сервер) +// Параметры: +// Наборы - Массив из см. ЮТФабрикаСлужебный.ОписаниеИсполняемогоНабораТестов - Наборы тестов модуля +// ТестовыйМодуль - см. ЮТФабрикаСлужебный.ОписаниеИсполняемогоТестовогоМодуля +// +// Возвращаемое значение: +// Массив из см. ЮТФабрикаСлужебный.ОписаниеИсполняемогоНабораТестов - Результат прогона наборов тестов с заполненной информацией о выполнении +Функция ВыполнитьГруппуНаборовТестов(Наборы, ТестовыйМодуль) Экспорт + + Если Наборы.Количество() = 0 Тогда + Возврат Наборы; + КонецЕсли; + + ЮТСобытияСлужебный.ПередВсемиТестамиМодуля(ТестовыйМодуль); + + Если ЕстьОшибки(ТестовыйМодуль) Тогда + СкопироватьОшибкиВ(Наборы, ТестовыйМодуль.Ошибки); + Возврат Наборы; + КонецЕсли; + + Для Каждого Набор Из Наборы Цикл + + Результат = ВыполнитьНаборТестов(Набор, ТестовыйМодуль); + + Если Результат <> Неопределено Тогда + Набор.Тесты = Результат; + КонецЕсли; + + КонецЦикла; + + ЮТСобытияСлужебный.ПослеВсехТестовМодуля(ТестовыйМодуль); + + Если ЕстьОшибки(ТестовыйМодуль) Тогда + СкопироватьОшибкиВ(Наборы, ТестовыйМодуль.Ошибки); + КонецЕсли; + + ТестовыйМодуль.Ошибки.Очистить(); // Эти ошибки используются как буфер и уже скопированы в наборы, но ломают последующие наборы + + Возврат Наборы; + +КонецФункции + +#КонецОбласти + +#Область СлужебныеПроцедурыИФункции + +Функция ВыполнитьНаборТестов(Набор, ТестовыйМодуль) + + Набор.ДатаСтарта = ТекущаяУниверсальнаяДатаВМиллисекундах(); + ЮТСобытияСлужебный.ПередТестовымНабором(ТестовыйМодуль, Набор); + + Если ЕстьОшибки(Набор) Тогда + Возврат Неопределено; + КонецЕсли; + + Результаты = Новый Массив(); + + Для Каждого Тест Из Набор.Тесты Цикл + + ВТранзакции = Ложь; + ПередКаждымТестом(ТестовыйМодуль, Набор, Тест, ВТранзакции); + + Тест.ДатаСтарта = ТекущаяУниверсальнаяДатаВМиллисекундах(); + ВыполнитьТестовыйМетод(Тест); + Тест.Длительность = ТекущаяУниверсальнаяДатаВМиллисекундах() - Тест.ДатаСтарта; + + ПослеКаждогоТеста(ТестовыйМодуль, Набор, Тест, ВТранзакции); + + Тест.Статус = ЮТРегистрацияОшибокСлужебный.СтатусВыполненияТеста(Тест); + Результаты.Добавить(Тест); + + КонецЦикла; + + ЮТСобытияСлужебный.ПослеТестовогоНабора(ТестовыйМодуль, Набор); + + Набор.Длительность = ТекущаяУниверсальнаяДатаВМиллисекундах() - Набор.ДатаСтарта; + + Возврат Результаты; + +КонецФункции + +Процедура ПередКаждымТестом(ТестовыйМодуль, Набор, Тест, ВТранзакции) + + ЮТСобытияСлужебный.УстановитьКонтекстИсполнения(ТестовыйМодуль, Набор, Тест); +#Если Сервер ИЛИ ТолстыйКлиентОбычноеПриложение ИЛИ ТолстыйКлиентУправляемоеПриложение Тогда + ВТранзакции = ЮТНастройкиВыполнения.ВТранзакции(); + Если ВТранзакции Тогда + НачатьТранзакцию(); + КонецЕсли; +#КонецЕсли + + ЮТСобытияСлужебный.ПередКаждымТестом(ТестовыйМодуль, Набор, Тест); + +КонецПроцедуры + +Процедура ПослеКаждогоТеста(ТестовыйМодуль, Набор, Тест, ВТранзакции) + + Если ЮТКонтекстСлужебный.ДанныеКонтекста() = Неопределено Тогда // Сломан контекст + ОбновитьПовторноИспользуемыеЗначения(); + ОтменитьТранзакциюТеста(Тест, ВТранзакции); + ЮТСобытияСлужебный.ПослеКаждогоТеста(ТестовыйМодуль, Набор, Тест); + Иначе + ЮТСобытияСлужебный.ПослеКаждогоТеста(ТестовыйМодуль, Набор, Тест); + ОтменитьТранзакциюТеста(Тест, ВТранзакции); + КонецЕсли; + +КонецПроцедуры + +Процедура ОтменитьТранзакциюТеста(Тест, ВТранзакции) + +#Если Сервер ИЛИ ТолстыйКлиентОбычноеПриложение ИЛИ ТолстыйКлиентУправляемоеПриложение Тогда + Если ВТранзакции Тогда + Если ТранзакцияАктивна() Тогда + ОтменитьТранзакцию(); + Иначе + ЮТРегистрацияОшибокСлужебный.ЗарегистрироватьПростуюОшибкуВыполнения(Тест, "Обнаружено лишне закрытие транзакции"); + КонецЕсли; + КонецЕсли; + + Пока ТранзакцияАктивна() Цикл + ОтменитьТранзакцию(); + ЮТРегистрацияОшибокСлужебный.ЗарегистрироватьПростуюОшибкуВыполнения(Тест, "Обнаружена незакрытая транзакция"); + КонецЦикла; +#КонецЕсли + +КонецПроцедуры + +Функция ЕстьОшибки(Объект) + + Возврат ЗначениеЗаполнено(Объект.Ошибки); + +КонецФункции + +Процедура ВыполнитьТестовыйМетод(Тест) + + Если ЕстьОшибки(Тест) Тогда + Возврат; + КонецЕсли; + + СтатусыИсполненияТеста = ЮТФабрика.СтатусыИсполненияТеста(); + Тест.Статус = СтатусыИсполненияТеста.Исполнение; + + Ошибка = ЮТМетодыСлужебный.ВыполнитьМетод(Тест.ПолноеИмяМетода, Тест.Параметры); + + Если Ошибка <> Неопределено Тогда + ЮТРегистрацияОшибокСлужебный.ЗарегистрироватьОшибкуВыполненияТеста(Тест, Ошибка); + КонецЕсли; + +КонецПроцедуры + +Процедура СкопироватьОшибкиВ(Объекты, Ошибки) + + Для Каждого Объект Из Объекты Цикл + + ЮТКоллекции.ДополнитьМассив(Объект.Ошибки, Ошибки); + + Если Объект.Свойство("Статус") Тогда + Объект.Статус = ЮТФабрика.СтатусыИсполненияТеста().Сломан; + КонецЕсли; + + КонецЦикла; + +КонецПроцедуры + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТКоллекции.xml b/src/cfe/YAXUnit/CommonModules/ЮТКоллекции.xml new file mode 100644 index 0000000..94f6bac --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТКоллекции.xml @@ -0,0 +1,23 @@ + + + + + ЮТКоллекции + + + ru + Коллекции + + + + false + true + true + false + true + false + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТКоллекции/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТКоллекции/Ext/Module.bsl new file mode 100644 index 0000000..647261e --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТКоллекции/Ext/Module.bsl @@ -0,0 +1,409 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область ПрограммныйИнтерфейс + +// Возвращает требуемое поле структуры. В случае отсутствия поля возвращает значение по умолчанию +// +// Параметры: +// ИсходнаяСтруктура - Структура - Исходная структура +// ИмяПоля - Строка - Имя поля структуры +// ЗначениеПоУмолчанию - Произвольный - Значение, которое будет возвращено, если поля в структуре нет +// +// Возвращаемое значение: +// Произвольный - Значение искомого поля структуры +Функция ЗначениеСтруктуры(ИсходнаяСтруктура, ИмяПоля, ЗначениеПоУмолчанию = Неопределено) Экспорт + + Если НЕ ЗначениеЗаполнено(ИсходнаяСтруктура) ИЛИ ПустаяСтрока(ИмяПоля) Тогда + Возврат ЗначениеПоУмолчанию; + КонецЕсли; + + ЗначениеПоля = Неопределено; + + Если ИсходнаяСтруктура.Свойство(ИмяПоля, ЗначениеПоля) Тогда + Возврат ЗначениеПоля; + КонецЕсли; + + Возврат ЗначениеПоУмолчанию; + +КонецФункции + +// Добавляет в приемник данные из источника, при совпадении ключей значения заменяются +// +// Параметры: +// Приемник - Структура +// Источник - Соответствие из Произвольный +// - Структура +Процедура ДополнитьСтруктуру(Приемник, Источник) Экспорт + + Для Каждого Элемент Из Источник Цикл + Приемник.Вставить(Элемент.Ключ, Элемент.Значение); + КонецЦикла; + +КонецПроцедуры + +// Добавляет в приемник все элементы источника +// +// Параметры: +// Приемник - Массив из Произвольный +// Источник - Массив из Произвольный +Процедура ДополнитьМассив(Приемник, Источник) Экспорт + + Для Каждого Элемент Из Источник Цикл + Приемник.Добавить(Элемент); + КонецЦикла; + +КонецПроцедуры + +// Создает копию экземпляра указанного объекта. +// Примечание: +// Функцию нельзя использовать для объектных типов (СправочникОбъект, ДокументОбъект и т.п.). +// +// Параметры: +// Источник - Произвольный - объект, который необходимо скопировать. +// +// Возвращаемое значение: +// Произвольный - копия объекта, переданного в параметре Источник. +// +Функция СкопироватьРекурсивно(Источник) Экспорт + + Перем Приемник; + + СкопироватьПрисвоением = Ложь; + + ТипИсточника = ТипЗнч(Источник); + + Если ЮТТипыДанныхСлужебный.ЭтоСтруктура(ТипИсточника) Тогда + Приемник = СкопироватьСтруктуру(Источник); + ИначеЕсли ЮТТипыДанныхСлужебный.ЭтоСоответствие(ТипИсточника) Тогда + Приемник = СкопироватьСоответствие(Источник); + ИначеЕсли ЮТТипыДанныхСлужебный.ЭтоМассива(ТипИсточника) Тогда + Приемник = СкопироватьМассив(Источник); + ИначеЕсли ТипИсточника = Тип("СписокЗначений") Тогда + Приемник = СкопироватьСписокЗначений(Источник); + Иначе + + СкопироватьПрисвоением = Истина; +#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда + + Если ТипИсточника = Тип("ТаблицаЗначений") Или ТипИсточника = Тип("ДеревоЗначений") Тогда + + СкопироватьПрисвоением = Ложь; + Приемник = Источник.Скопировать(); + + КонецЕсли; +#КонецЕсли + + КонецЕсли; + + Если СкопироватьПрисвоением Тогда + Приемник = Источник; + КонецЕсли; + + Возврат Приемник; + +КонецФункции + +// Создает копию структуры +// +// Параметры: +// Источник - Структура, ФиксированнаяСтруктура - копируемая структура +// +// Возвращаемое значение: +// Структура - копия исходной структуры. +Функция СкопироватьСтруктуру(Источник) Экспорт + + Результат = Новый Структура; + + Для Каждого КлючИЗначение Из Источник Цикл + Результат.Вставить(КлючИЗначение.Ключ, СкопироватьРекурсивно(КлючИЗначение.Значение)); + КонецЦикла; + + Возврат Результат; + +КонецФункции + +// Создает копию соответствия +// +// Параметры: +// Источник - Соответствие из Произвольный +// - ФиксированноеСоответствие из Произвольный +// +// Возвращаемое значение: +// Соответствие Из Произвольный - копия исходного соответствия. +// +Функция СкопироватьСоответствие(Источник) Экспорт + + Результат = Новый Соответствие; + + Для Каждого КлючИЗначение Из Источник Цикл + + НовыйКлюч = СкопироватьРекурсивно(КлючИЗначение.Ключ); + НовоеЗначение = СкопироватьРекурсивно(КлючИЗначение.Значение); + Результат.Вставить(НовыйКлюч, НовоеЗначение); + + КонецЦикла; + + Возврат Результат; + +КонецФункции + +// Создает копию массива +// +// Параметры: +// Источник - Массив Из Произвольный +// - ФиксированныйМассив из Произвольный +// +// Возвращаемое значение: +// Массив Из Произвольный - копия исходного массива. +Функция СкопироватьМассив(Источник) Экспорт + + Если НЕ ЗначениеЗаполнено(Источник) Тогда + Возврат Новый Массив; + КонецЕсли; + + Размер = Источник.Количество(); + Результат = Новый Массив(Размер); + + Для Инд = 0 По Размер - 1 Цикл + Результат[Инд] = СкопироватьРекурсивно(Источник[Инд]); + КонецЦикла; + + Возврат Результат; + +КонецФункции + +// Создает копию списка значений +// +// Параметры: +// Источник - СписокЗначений Из Произвольный +// +// Возвращаемое значение: +// СписокЗначений Из Произвольный +// +Функция СкопироватьСписокЗначений(Источник) Экспорт + + Результат = Новый СписокЗначений; + + Для Каждого ЭлементСписка Из Источник Цикл + + НовоеЗначение = СкопироватьРекурсивно(ЭлементСписка.Значение); + Результат.Добавить(НовоеЗначение, ЭлементСписка.Представление, ЭлементСписка.Пометка, ЭлементСписка.Картинка); + + КонецЦикла; + + Возврат Результат; + +КонецФункции + +// Выгружает значения "колонки" коллекции элементов. +// +// Параметры: +// Коллекция - Произвольный - Итерируемая коллекция +// ИмяРеквизита - Строка - Имя реквизата элементов коллекции +// +// Возвращаемое значение: +// Массив из Произвольный +Функция ВыгрузитьЗначения(Коллекция, ИмяРеквизита) Экспорт + + Результат = Новый Массив(); + + Для Каждого ЭлементКоллекции Из Коллекция Цикл + Результат.Добавить(ЭлементКоллекции[ИмяРеквизита]); + КонецЦикла; + + Возврат Результат; + +КонецФункции + +// Вычисляет двух массивов, коллекцию содержащую общие элементы. +// +// Параметры: +// Коллекция1 - Массив из Произвольный +// Коллекция2 - Массив из Произвольный +// +// Возвращаемое значение: +// Массив из Произвольный - Пересечение массивов +Функция ПересечениеМассивов(Коллекция1, Коллекция2) Экспорт + + Результат = Новый Массив; + + Для Каждого Элемент Из Коллекция1 Цикл + + Если Коллекция2.Найти(Элемент) <> Неопределено Тогда + Результат.Добавить(Элемент); + КонецЕсли; + + КонецЦикла; + + Возврат Результат; + +КонецФункции + +// Создает массив с переданными значениями +// +// Параметры: +// Значение - Произвольный +// Значение2 - Произвольный +// Значение3 - Произвольный +// Значение4 - Произвольный +// Значение5 - Произвольный +// Значение6 - Произвольный +// Значение7 - Произвольный +// Значение8 - Произвольный +// Значение9 - Произвольный +// Значение10 - Произвольный +// +// Возвращаемое значение: +// Массив из Произвольный +//@skip-check method-too-many-params +Функция ЗначениеВМассиве(Значение, + Значение2 = "_!%*", + Значение3 = "_!%*", + Значение4 = "_!%*", + Значение5 = "_!%*", + Значение6 = "_!%*", + Значение7 = "_!%*", + Значение8 = "_!%*", + Значение9 = "_!%*", + Значение10 = "_!%*") Экспорт + + Значения = Новый Массив; + + Если Не ДобавитьНеПоследнее(Значения, Значение) Тогда + Возврат Значения; + КонецЕсли; + + Если Не ДобавитьНеПоследнее(Значения, Значение2) Тогда + Возврат Значения; + КонецЕсли; + + Если Не ДобавитьНеПоследнее(Значения, Значение3) Тогда + Возврат Значения; + КонецЕсли; + + Если Не ДобавитьНеПоследнее(Значения, Значение4) Тогда + Возврат Значения; + КонецЕсли; + + Если Не ДобавитьНеПоследнее(Значения, Значение5) Тогда + Возврат Значения; + КонецЕсли; + + Если Не ДобавитьНеПоследнее(Значения, Значение6) Тогда + Возврат Значения; + КонецЕсли; + + Если Не ДобавитьНеПоследнее(Значения, Значение7) Тогда + Возврат Значения; + КонецЕсли; + + Если Не ДобавитьНеПоследнее(Значения, Значение8) Тогда + Возврат Значения; + КонецЕсли; + + Если Не ДобавитьНеПоследнее(Значения, Значение9) Тогда + Возврат Значения; + КонецЕсли; + + Если Не ДобавитьНеПоследнее(Значения, Значение10) Тогда + Возврат Значения; + КонецЕсли; + + Возврат Значения; + +КонецФункции + +// Возвращает соответствие элементов переданной коллекции, в качестве ключей выступают значения указанного поля элементов коллекции. +// +// Параметры: +// Коллекция - Произвольный - значение, для которого определен итератор, и возможно обращение к полям элементов через квадратные скобки. +// ИмяПоляКлюча - Строка - имя поля элемента коллекции, которое будет ключом соответствия. +// ИмяПоляЗначения - Строка - если указан, значениями результата будут не элементы, а значения соответствующих полей элементов коллекции. +// Возвращаемое значение: +// Соответствие Из Произвольный - полученное соответствие. +Функция ВСоответствие(Коллекция, ИмяПоляКлюча, ИмяПоляЗначения = Неопределено) Экспорт + + Результат = Новый Соответствие(); + + Для Каждого ЭлементКоллекции Из Коллекция Цикл + + Значение = ?(ИмяПоляЗначения = Неопределено, ЭлементКоллекции, ЭлементКоллекции[ИмяПоляЗначения]); + + Результат.Вставить(ЭлементКоллекции[ИмяПоляКлюча], Значение); + + КонецЦикла; + + Возврат Результат; + +КонецФункции + +// Возвращает структуру элементов переданной коллекции, в качестве ключей выступают значения указанного поля элементов коллекции. +// +// Параметры: +// Коллекция - Произвольный - значение, для которого определен итератор, и возможно обращение к полям элементов через квадратные скобки. +// ИмяПоляКлюча - Строка - имя поля элемента коллекции, которое будет ключом соответствия. +// ИмяПоляЗначения - Строка - если указан, значениями результата будут не элементы, а значения соответствующих полей элементов коллекции. +// Возвращаемое значение: +// Структура Из Произвольный - полученная структура. +Функция ВСтруктуру(Коллекция, ИмяПоляКлюча, ИмяПоляЗначения = Неопределено) Экспорт + + Результат = Новый Структура(); + + Для Каждого ЭлементКоллекции Из Коллекция Цикл + + Значение = ?(ИмяПоляЗначения = Неопределено, ЭлементКоллекции, ЭлементКоллекции[ИмяПоляЗначения]); + + Результат.Вставить(ЭлементКоллекции[ИмяПоляКлюча], Значение); + + КонецЦикла; + + Возврат Результат; + +КонецФункции + +// Формирует текстовое представление массива. +// Пример результата - "[1, 2, 3]" +// +// Параметры: +// Данные - Массив из Строка +// +// Возвращаемое значение: +// Строка +Функция ПредставлениеМассива(Данные) Экспорт + + Возврат СтрШаблон("[%1]", СтрСоединить(Данные, ", ")); + +КонецФункции + +#КонецОбласти + +#Область СлужебныеПроцедурыИФункции + +Функция ДобавитьНеПоследнее(Значения, Значение, ФлагОкончания = "_!%*") + + Если Значение <> ФлагОкончания Тогда + Значения.Добавить(Значение); + Возврат Истина; + КонецЕсли; + + Возврат Ложь; + +КонецФункции + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТКомпоненты.xml b/src/cfe/YAXUnit/CommonModules/ЮТКомпоненты.xml new file mode 100644 index 0000000..c116169 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТКомпоненты.xml @@ -0,0 +1,23 @@ + + + + + ЮТКомпоненты + + + ru + Компоненты + + + + false + true + true + false + true + false + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТКомпоненты/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТКомпоненты/Ext/Module.bsl new file mode 100644 index 0000000..6732b4d --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТКомпоненты/Ext/Module.bsl @@ -0,0 +1,160 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область ПрограммныйИнтерфейс + +// Возвращает внешнюю компоненту, реализующую паузу +// Предоставляет метод `Ожидать`, `Sleep` +// +// Возвращаемое значение: +// ВнешнийОбъект +Функция Пауза() Экспорт + + Возврат СоздатьКомпоненту(ОписаниеКомпонентыСервисногоНазначения(), Истина); + +КонецФункции + +// Возвращает внешнюю компоненту, реализующую вывод в консоль +// Предоставляет метод `Напечатать`, `Print` +// +// Возвращаемое значение: +// ВнешнийОбъект +Функция Консоль() Экспорт + + Возврат СоздатьКомпоненту(ОписаниеКомпонентыСервисногоНазначения(), Истина); + +КонецФункции + +// Возвращает внешнюю компоненту, реализующую функциональность регулярных выражений +// Подробнее с документацией можно ознакомиться по ссылке: https://github.com/alexkmbk/RegEx1CAddin +// +// Возвращаемое значение: +// ВнешнийОбъект +Функция РегулярныеВыражения() Экспорт + +#Если НЕ Сервер Тогда + Если НЕ ЮТМетаданные.РазрешеныСинхронныеВызовы() Тогда + ВызватьИсключение "Компонента регулярных выражений не доступна на клиенте при отключении синхронных вызовов"; + КонецЕсли; +#КонецЕсли + + Компонента = СоздатьКомпоненту(ОписаниеКомпонентыРегулярныхВыражений()); + Компонента.ВызыватьИсключения = Истина; + Возврат Компонента; + +КонецФункции + +#КонецОбласти + +#Область СлужебныйПрограммныйИнтерфейс + +// Создает внешнюю компоненту по описанию +// +// Параметры: +// ОписаниеКомпоненты - см. ОписаниеКомпоненты +// Кэшировать - Булево - Кэшировать созданную компоненту +// +// Возвращаемое значение: +// ВнешнийОбъект +Функция СоздатьКомпоненту(ОписаниеКомпоненты, Кэшировать = Ложь) Экспорт + + Если Кэшировать Тогда + Возврат ЮТСлужебныйПовторногоИспользования.СоздатьКомпоненту(ОписаниеКомпоненты); + КонецЕсли; + +#Если Сервер Тогда + Подключена = ПодключитьКомпоненту(ОписаниеКомпоненты.ИмяМакета, ОписаниеКомпоненты.ИмяКомпоненты, Истина); +#Иначе + Если ЮТМетаданные.РазрешеныСинхронныеВызовы() Тогда + Подключена = ПодключитьКомпоненту(ОписаниеКомпоненты.ИмяМакета, ОписаниеКомпоненты.ИмяКомпоненты, Истина); + Иначе + Подключена = Истина; // Подключены при старте системы + КонецЕсли; +#КонецЕсли + + Если Подключена Тогда + Возврат Новый (ОписаниеКомпоненты.ИмяКласса); + Иначе + ВызватьИсключение "Не удалось подключить внешнюю компоненту " + ОписаниеКомпоненты.ИмяКласса; + КонецЕсли; + +КонецФункции + +// Подключает внещнюю компоненту из макета +// +// Параметры: +// ИмяМакета - Строка - Имя макета, в котором хранится компонента +// ИмяКомпоненты - Строка - Имя компоненты +// Кэшировать - Булево - Кэшировать создание компоненты +// +// Возвращаемое значение: +// Булево - Успешность подключения +Функция ПодключитьКомпоненту(ИмяМакета, ИмяКомпоненты, Кэшировать) Экспорт + + Если Кэшировать Тогда + Возврат ЮТСлужебныйПовторногоИспользования.ПодключитьКомпоненту(ИмяМакета, ИмяКомпоненты); + КонецЕсли; + + Возврат ПодключитьВнешнююКомпоненту(ИмяМакета, ИмяКомпоненты, ТипВнешнейКомпоненты.Native); + +КонецФункции + +// Описание компоненты, реализующей паузу, консоль и другие +// +// Возвращаемое значение: +// см. ОписаниеКомпоненты +Функция ОписаниеКомпонентыСервисногоНазначения() Экспорт + + Возврат ОписаниеКомпоненты("ОбщийМакет.ЮТYaxUnitAddIn", "YaxUnitAddin", "Common"); + +КонецФункции + +// Описание компоненты реализующей функциональность регулярных выражений. +// +// Возвращаемое значение: +// см. ОписаниеКомпоненты +Функция ОписаниеКомпонентыРегулярныхВыражений() Экспорт + + Возврат ОписаниеКомпоненты("ОбщийМакет.ЮТRegEx1CAddin", "RegEx1CAddin", "RegEx"); + +КонецФункции + +// Описание внешней компоненты. +// +// Параметры: +// ИмяМакета - Строка - Имя макета, в котором хранится компонента +// ИмяКомпоненты - Строка -Имя компоненты +// ИмяКласса - Строка - Имя класса, по которому создается компонента +// +// Возвращаемое значение: +// Структура - Описание компоненты: +// * ИмяМакета - Строка - Имя макета, в котором хранится компонента +// * ИмяКомпоненты - Строка -Имя компоненты +// * ИмяКласса - Строка - Имя класса +Функция ОписаниеКомпоненты(ИмяМакета, ИмяКомпоненты, ИмяКласса) Экспорт + + Описание = Новый Структура; + Описание.Вставить("ИмяМакета", ИмяМакета); + Описание.Вставить("ИмяКомпоненты", ИмяКомпоненты); + Описание.Вставить("ИмяКласса", СтрШаблон("AddIn.%1.%2", ИмяКомпоненты, ИмяКласса)); + + Возврат Описание; + +КонецФункции + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТКомпонентыСлужебныйВызовСервера.xml b/src/cfe/YAXUnit/CommonModules/ЮТКомпонентыСлужебныйВызовСервера.xml new file mode 100644 index 0000000..6c1a206 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТКомпонентыСлужебныйВызовСервера.xml @@ -0,0 +1,23 @@ + + + + + ЮТКомпонентыСлужебныйВызовСервера + + + ru + Компоненты вызов сервера + + + + false + false + true + false + false + true + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТКомпонентыСлужебныйВызовСервера/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТКомпонентыСлужебныйВызовСервера/Ext/Module.bsl new file mode 100644 index 0000000..839372a --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТКомпонентыСлужебныйВызовСервера/Ext/Module.bsl @@ -0,0 +1,108 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область СлужебныйПрограммныйИнтерфейс + +Функция ФайлКомпоненты(Знач ИмяМакета, Знач ОперационнаяСистема, Знач Архитектура) Экспорт + + Данные = ЮТОбщийСлужебныйВызовСервера.Макет(ИмяМакета); + ЧтениеАрхива = Новый ЧтениеZipФайла(); + ЧтениеАрхива.Открыть(Данные.ОткрытьПотокДляЧтения()); + + ИмяФайлаКомпоненты = ИмяФайлаКомпоненты(ЧтениеАрхива, ОперационнаяСистема, Архитектура); + + Если ИмяФайлаКомпоненты = Неопределено Тогда + ВызватьИсключение "Компонента не поддерживает клиентское окружение"; + КонецЕсли; + + Данные = ДвоичныеДанныеЭлемента(ЧтениеАрхива, ИмяФайлаКомпоненты); + + Возврат Новый ФиксированнаяСтруктура("ИмяФайла, Данные", ИмяФайлаКомпоненты, Данные); + +КонецФункции + +#КонецОбласти + +#Область СлужебныеПроцедурыИФункции + +Функция ИмяФайлаКомпоненты(ЧтениеАрхива, ОперационнаяСистема, Архитектура) + + Данные = ДвоичныеДанныеЭлемента(ЧтениеАрхива, "MANIFEST.XML"); + + Если Данные = Неопределено Тогда + ВызватьИсключение "Архив компоненты не содержит манифеста"; + КонецЕсли; + + ЧтениеXML = Новый ЧтениеXML(); + ЧтениеXML.ОткрытьПоток(Данные.ОткрытьПотокДляЧтения()); + + ИмяФайлаКомпоненты = Неопределено; + + Пока ЧтениеXML.Прочитать() Цикл + + Если ЭтоПодходящийУзел(ЧтениеXML, ОперационнаяСистема, Архитектура) Тогда + ИмяФайлаКомпоненты = ЧтениеXML.ЗначениеАтрибута("path"); + Прервать; + КонецЕсли; + + КонецЦикла; + + ЧтениеXML.Закрыть(); + + Возврат ИмяФайлаКомпоненты; + +КонецФункции + +Функция ЭтоПодходящийУзел(ЧтениеXML, ОперационнаяСистема, Архитектура) + + Если ЧтениеXML.ТипУзла <> ТипУзлаXML.НачалоЭлемента ИЛИ СтрСравнить(ЧтениеXML.Имя, "component") <> 0 Тогда + Возврат Ложь; + КонецЕсли; + + ОперационнаяСистемаУзла = ЧтениеXML.ЗначениеАтрибута("os"); + АрхитектураУзла = ЧтениеXML.ЗначениеАтрибута("arch"); + + Возврат ОперационнаяСистема = ОперационнаяСистемаУзла И Архитектура = АрхитектураУзла; + +КонецФункции + +Функция ДвоичныеДанныеЭлемента(ЧтениеАрхива, ИмяФайла) + + ЭлементФайла = Неопределено; + + Для Каждого Элемент Из ЧтениеАрхива.Элементы Цикл + Если СтрСравнить(Элемент.ПолноеИмя, ИмяФайла) = 0 Тогда + ЭлементФайла = Элемент; + КонецЕсли; + КонецЦикла; + + Если ЭлементФайла = Неопределено Тогда + Возврат Неопределено; + КонецЕсли; + + ИмяВременногоФайла = ПолучитьИмяВременногоФайла(); + ЧтениеАрхива.Извлечь(ЭлементФайла, ИмяВременногоФайла, РежимВосстановленияПутейФайловZIP.НеВосстанавливать); + + Данные = Новый ДвоичныеДанные(ЮТФайлы.ОбъединитьПути(ИмяВременногоФайла, ИмяФайла)); + УдалитьФайлы(ИмяВременногоФайла); + + Возврат Данные; + +КонецФункции + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТКомпонентыСлужебныйКлиент.xml b/src/cfe/YAXUnit/CommonModules/ЮТКомпонентыСлужебныйКлиент.xml new file mode 100644 index 0000000..4fa2153 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТКомпонентыСлужебныйКлиент.xml @@ -0,0 +1,23 @@ + + + + + ЮТКомпонентыСлужебныйКлиент + + + ru + Компоненты клиент + + + + false + true + false + false + true + false + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТКомпонентыСлужебныйКлиент/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТКомпонентыСлужебныйКлиент/Ext/Module.bsl new file mode 100644 index 0000000..a750803 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТКомпонентыСлужебныйКлиент/Ext/Module.bsl @@ -0,0 +1,220 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область СлужебныйПрограммныйИнтерфейс + +Процедура ТихаяУстановкаКомпонент(ОбработчикЗавершения) Экспорт + + ПараметрыТихойУстановки = ПараметрыТихойУстановки(); + ПараметрыТихойУстановки.Компоненты.Добавить(ЮТКомпоненты.ОписаниеКомпонентыСервисногоНазначения()); + ПараметрыТихойУстановки.Компоненты.Добавить(ЮТКомпоненты.ОписаниеКомпонентыРегулярныхВыражений()); + + ЮТАсинхроннаяОбработкаСлужебныйКлиент.ДобавитьОбработчикЦепочки(ПараметрыТихойУстановки, + ЭтотОбъект, + "УстановитьПараметрыОкружения"); + ЮТАсинхроннаяОбработкаСлужебныйКлиент.ДобавитьОбработчикЦепочки(ПараметрыТихойУстановки, + ЭтотОбъект, + "ТихаяУстановкаВнешнихКомпонент"); + + ЮТАсинхроннаяОбработкаСлужебныйКлиент.ДобавитьОбработчикЦепочки(ПараметрыТихойУстановки, + ЭтотОбъект, + "ТихаяУстановкаВнешнихКомпонент"); + Если НЕ ЮТМетаданные.РазрешеныСинхронныеВызовы() Тогда + ЮТАсинхроннаяОбработкаСлужебныйКлиент.ДобавитьОбработчикЦепочки(ПараметрыТихойУстановки, + ЭтотОбъект, + "ПодключениеВнешнихКомпонент"); + КонецЕсли; + + ПараметрыТихойУстановки.Цепочка.Добавить(ОбработчикЗавершения); + + Обработчик = ЮТАсинхроннаяОбработкаСлужебныйКлиент.СледующийОбработчик(ПараметрыТихойУстановки); + НачатьПолучениеРабочегоКаталогаДанныхПользователя(Обработчик); + +КонецПроцедуры + +#КонецОбласти + +#Область СлужебныеПроцедурыИФункции + +Функция ПараметрыТихойУстановки() + + ПараметрыТихойУстановки = ЮТАсинхроннаяОбработкаСлужебныйКлиент.ЦепочкаАсинхроннойОбработки(); + ПараметрыТихойУстановки.Вставить("Компоненты", Новый Массив()); + ПараметрыТихойУстановки.Вставить("РабочийКаталог", ""); + ПараметрыТихойУстановки.Вставить("ОперационнаяСистема", ""); + ПараметрыТихойУстановки.Вставить("Архитектура", ""); + ПараметрыТихойУстановки.Вставить("ДанныеРеестра", ""); + ПараметрыТихойУстановки.Вставить("ИзмененРеестр", Ложь); + ПараметрыТихойУстановки.Вставить("ПодключенныеКомпоненты", Новый Массив()); + + Возврат ПараметрыТихойУстановки; + +КонецФункции + +Процедура УстановитьПараметрыОкружения(Результат, ПараметрыТихойУстановки) Экспорт + + КорневойКаталог = ЮТФайлы.ОбъединитьПути(Результат, "..", "..", ".."); + КаталогКомпонент = ЮТФайлы.ОбъединитьПути(КорневойКаталог, "ExtCompT"); + + ПараметрыТихойУстановки.РабочийКаталог = КаталогКомпонент; + Информация = Новый СистемнаяИнформация(); + ОперационнаяСистема = Неопределено; + Архитектура = Неопределено; + + Linux = "Linux"; + Windows = "Windows"; + MacOS = "MacOS"; + + //@skip-check bsl-variable-name-invalid + x86 = "i386"; + //@skip-check bsl-variable-name-invalid + x64 = "x86_64"; + + ТипКлиентскойПлатформы = Информация.ТипПлатформы; + + Если ТипКлиентскойПлатформы = ТипПлатформы.Linux_x86 Тогда + ОперационнаяСистема = Linux; + Архитектура = x86; + ИначеЕсли ТипКлиентскойПлатформы = ТипПлатформы.Linux_x86_64 Тогда + ОперационнаяСистема = Linux; + Архитектура = x64; + ИначеЕсли ТипКлиентскойПлатформы = ТипПлатформы.Windows_x86 Тогда + ОперационнаяСистема = Windows; + Архитектура = x86; + ИначеЕсли ТипКлиентскойПлатформы = ТипПлатформы.Windows_x86_64 Тогда + ОперационнаяСистема = Windows; + Архитектура = x64; + ИначеЕсли ТипКлиентскойПлатформы = ТипПлатформы.MacOS_x86 Тогда + ОперационнаяСистема = MacOS; + Архитектура = x86; + ИначеЕсли ТипКлиентскойПлатформы = ТипПлатформы.MacOS_x86_64 Тогда + ОперационнаяСистема = MacOS; + Архитектура = x64; + Иначе + ЮТИсполнительСлужебныйКлиент.ОбработкаОшибки("Неподдерживаемый тип платформы"); + КонецЕсли; + + ПараметрыТихойУстановки.ОперационнаяСистема = ОперационнаяСистема; + ПараметрыТихойУстановки.Архитектура = Архитектура; + ЮТАсинхроннаяОбработкаСлужебныйКлиент.ВызватьСледующийОбработчик(ПараметрыТихойУстановки); + +КонецПроцедуры + +Процедура ПрочитатьФайлRegistry(ПараметрыТихойУстановки) Экспорт + +#Если ВебКлиент Тогда + ЮТИсполнительСлужебныйКлиент.ОбработкаОшибки(ЮТИсключения.МетодНеДоступен("ЮТКомпонентыКлиент.ПрочитатьФайлRegistry")); + Возврат; +#Иначе + ФайлРеестра = ЮТФайлы.ОбъединитьПути(ПараметрыТихойУстановки.РабочийКаталог, "registry.xml"); + Чтение = Новый ЧтениеТекста(ФайлРеестра); + Данные = Чтение.Прочитать(); + Чтение.Закрыть(); + ПараметрыТихойУстановки.ДанныеРеестра = Данные; + +#КонецЕсли + +КонецПроцедуры + +Процедура ЗаписатьФайлRegistry(ПараметрыТихойУстановки) Экспорт + +#Если ВебКлиент Тогда + ЮТИсполнительСлужебныйКлиент.ОбработкаОшибки(ЮТИсключения.МетодНеДоступен("ЮТКомпонентыКлиент.ЗаписатьФайлRegistry")); + Возврат; +#Иначе + Если ПараметрыТихойУстановки.ИзмененРеестр Тогда + ФайлРеестра = ЮТФайлы.ОбъединитьПути(ПараметрыТихойУстановки.РабочийКаталог, "registry.xml"); + Запись = Новый ЗаписьТекста(ФайлРеестра); + Запись.Записать(ПараметрыТихойУстановки.ДанныеРеестра); + Запись.Закрыть(); + КонецЕсли; +#КонецЕсли + +КонецПроцедуры + +Процедура ТихаяУстановкаВнешнихКомпонент(Результат, ПараметрыТихойУстановки) Экспорт + + ПрочитатьФайлRegistry(ПараметрыТихойУстановки); + + Для Каждого Компонента Из ПараметрыТихойУстановки.Компоненты Цикл + ТихаяУстановкаВнешнейКомпоненты(Компонента, ПараметрыТихойУстановки); + КонецЦикла; + + ЗаписатьФайлRegistry(ПараметрыТихойУстановки); + + ЮТАсинхроннаяОбработкаСлужебныйКлиент.ВызватьСледующийОбработчик(ПараметрыТихойУстановки); + +КонецПроцедуры + +Процедура ПодключениеВнешнихКомпонент(Результат, ПараметрыТихойУстановки) Экспорт + + КомпонентаДляПодключения = Неопределено; + + Для Каждого Компонента Из ПараметрыТихойУстановки.Компоненты Цикл + Если ПараметрыТихойУстановки.ПодключенныеКомпоненты.Найти(Компонента) = Неопределено Тогда + КомпонентаДляПодключения = Компонента; + Прервать; + КонецЕсли; + КонецЦикла; + + Если КомпонентаДляПодключения = Неопределено Тогда + ЮТАсинхроннаяОбработкаСлужебныйКлиент.ВызватьСледующийОбработчик(ПараметрыТихойУстановки); + Возврат; + КонецЕсли; + + ПараметрыТихойУстановки.ПодключенныеКомпоненты.Добавить(КомпонентаДляПодключения); + Обработчик = ЮТАсинхроннаяОбработкаСлужебныйКлиент.ТекущийОбработчик(ПараметрыТихойУстановки); + НачатьПодключениеВнешнейКомпоненты(Обработчик, + КомпонентаДляПодключения.ИмяМакета, + КомпонентаДляПодключения.ИмяКомпоненты, + ТипВнешнейКомпоненты.Native); + +КонецПроцедуры + +Процедура ТихаяУстановкаВнешнейКомпоненты(Компонента, Параметры) + + ДанныеФайла = ЮТКомпонентыСлужебныйВызовСервера.ФайлКомпоненты(Компонента.ИмяМакета, Параметры.ОперационнаяСистема, Параметры.Архитектура); + + Если ЗаписатьВРеестр(Параметры.ДанныеРеестра, ДанныеФайла.ИмяФайла) Тогда + Параметры.ИзмененРеестр = Истина; + КонецЕсли; + + ФайлКомпоненты = ЮТФайлы.ОбъединитьПути(Параметры.РабочийКаталог, ДанныеФайла.ИмяФайла); + ДанныеФайла.Данные.Записать(ФайлКомпоненты); + +КонецПроцедуры + +Функция ЗаписатьВРеестр(ДанныеРеестра, ИмяФайла) + + Если СтрНайти(ДанныеРеестра, " + | + | + |", ИмяФайла); + ИначеЕсли СтрНайти(ДанныеРеестра, СтрШаблон("path=""%1""", ИмяФайла)) <> 0 Тогда // Компонента уже зарегистрированна + Возврат Ложь; + Иначе // Добавляем компоненту + Запись = СтрШаблон(" ", ИмяФайла); + ДанныеРеестра = СтрЗаменить(ДанныеРеестра, "", Запись + Символы.ПС + ""); + КонецЕсли; + + Возврат Истина; + +КонецФункции + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТКонструкторВариантов.xml b/src/cfe/YAXUnit/CommonModules/ЮТКонструкторВариантов.xml new file mode 100644 index 0000000..27fc5be --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТКонструкторВариантов.xml @@ -0,0 +1,23 @@ + + + + + ЮТКонструкторВариантов + + + ru + Конструктор вариантов + + + + false + true + true + false + true + false + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТКонструкторВариантов/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТКонструкторВариантов/Ext/Module.bsl new file mode 100644 index 0000000..9ceb2ff --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТКонструкторВариантов/Ext/Module.bsl @@ -0,0 +1,108 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область ПрограммныйИнтерфейс + +// Инициализирует новый конструктор вариантов +// +// Параметры: +// Реквизиты - Строка - Имена реквизитов варианта разделенные запятыми. +// +// Возвращаемое значение: +// ОбщийМодуль - Этот же модуль, для замыкания +Функция Варианты(Реквизиты) Экспорт + + Варианты = Новый Структура("Реквизиты, Варианты, КоличествоРеквизитов", Реквизиты, Новый Массив()); + Вариант = Новый Структура(Реквизиты); + Варианты.КоличествоРеквизитов = Вариант.Количество(); + + ЮТКонтекстСлужебный.УстановитьЗначениеКонтекста(КлючКонтекста(), Варианты); + + Возврат ЮТКонструкторВариантов; + +КонецФункции + +// Добавляет новый вариант +// +// Параметры: +// Параметр1 - Произвольный +// Параметр2 - Произвольный +// Параметр3 - Произвольный +// Параметр4 - Произвольный +// Параметр5 - Произвольный +// Параметр6 - Произвольный +// Параметр7 - Произвольный +// +// Возвращаемое значение: +// ОбщийМодуль - Этот же модуль, для замыкания +//@skip-check method-too-many-params +Функция Добавить(Параметр1, + Параметр2 = Неопределено, + Параметр3 = Неопределено, + Параметр4 = Неопределено, + Параметр5 = Неопределено, + Параметр6 = Неопределено, + Параметр7 = Неопределено) Экспорт +// BSLLS:MagicNumber-off +// BSLLS:NumberOfValuesInStructureConstructor-off + Варианты = ЮТКонтекстСлужебный.ЗначениеКонтекста(КлючКонтекста()); + + Если Варианты.КоличествоРеквизитов = 1 Тогда + Вариант = Новый Структура(Варианты.Реквизиты, Параметр1); + ИначеЕсли Варианты.КоличествоРеквизитов = 2 Тогда + Вариант = Новый Структура(Варианты.Реквизиты, Параметр1, Параметр2); + ИначеЕсли Варианты.КоличествоРеквизитов = 3 Тогда + Вариант = Новый Структура(Варианты.Реквизиты, Параметр1, Параметр2, Параметр3); + ИначеЕсли Варианты.КоличествоРеквизитов = 4 Тогда + Вариант = Новый Структура(Варианты.Реквизиты, Параметр1, Параметр2, Параметр3, Параметр4); + ИначеЕсли Варианты.КоличествоРеквизитов = 5 Тогда + Вариант = Новый Структура(Варианты.Реквизиты, Параметр1, Параметр2, Параметр3, Параметр4, Параметр5); + ИначеЕсли Варианты.КоличествоРеквизитов = 6 Тогда + Вариант = Новый Структура(Варианты.Реквизиты, Параметр1, Параметр2, Параметр3, Параметр4, Параметр5, Параметр6); + ИначеЕсли Варианты.КоличествоРеквизитов = 7 Тогда + Вариант = Новый Структура(Варианты.Реквизиты, Параметр1, Параметр2, Параметр3, Параметр4, Параметр5, Параметр6, Параметр7); + КонецЕсли; +// BSLLS:NumberOfValuesInStructureConstructor-on +// BSLLS:MagicNumber-on + Варианты.Варианты.Добавить(Вариант); + + Возврат ЮТКонструкторВариантов; + +КонецФункции + +// Список вариантов. +// +// Возвращаемое значение: +// Массив из Структура +Функция СписокВариантов() Экспорт + + Возврат ЮТКонтекстСлужебный.ЗначениеКонтекста(КлючКонтекста()).Варианты; + +КонецФункции + +#КонецОбласти + +#Область СлужебныеПроцедурыИФункции + +Функция КлючКонтекста() + + Возврат "ВариантыТеста"; + +КонецФункции + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТКонструкторТестовыхДанныхСлужебный.xml b/src/cfe/YAXUnit/CommonModules/ЮТКонструкторТестовыхДанныхСлужебный.xml new file mode 100644 index 0000000..f048d79 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТКонструкторТестовыхДанныхСлужебный.xml @@ -0,0 +1,23 @@ + + + + + ЮТКонструкторТестовыхДанныхСлужебный + + + ru + Конструктор тестовых данных + + + + false + true + true + false + true + false + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТКонструкторТестовыхДанныхСлужебный/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТКонструкторТестовыхДанныхСлужебный/Ext/Module.bsl new file mode 100644 index 0000000..2e3a624 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТКонструкторТестовыхДанныхСлужебный/Ext/Module.bsl @@ -0,0 +1,292 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область СлужебныйПрограммныйИнтерфейс + +Процедура Установить(Контекст, ИмяРеквизита, Значение) Экспорт + + ОписаниеРеквизита(Контекст, ИмяРеквизита); // Проверка наличия реквизита + + ТекущаяЗапись = ТекущаяЗапись(Контекст); + ТекущаяЗапись.Вставить(ИмяРеквизита, Значение); + +КонецПроцедуры + +Процедура УстановитьРеквизиты(Контекст, ЗначенияРеквизитов) Экспорт + + ТекущаяЗапись = ТекущаяЗапись(Контекст); + Для Каждого ЗначениеРеквизита Из ЗначенияРеквизитов Цикл + + ОписаниеРеквизита(Контекст, ЗначениеРеквизита.Ключ); + ТекущаяЗапись.Вставить(ЗначениеРеквизита.Ключ, ЗначениеРеквизита.Значение); + + КонецЦикла; + +КонецПроцедуры + +Процедура Фикция(Контекст, ИмяРеквизита, РеквизитыЗаполнения, Знач ОграничениеТипа) Экспорт + + ЮТПроверкиСлужебный.ПроверитьТипПараметра(ОграничениеТипа, "Тип, ОписаниеТипов, Строка", "Фикция", "ЮТКонструкторТестовыхДанных", Истина); + + ТекущаяЗапись = ТекущаяЗапись(Контекст); + ОписаниеРеквизита = ОписаниеРеквизита(Контекст, ИмяРеквизита); + + Если ОграничениеТипа <> Неопределено Тогда + ПолноеИмяРеквизита = ЮТСтроки.ДобавитьСтроку(Контекст.ТекущаяТабличнаяЧасть, ИмяРеквизита, "."); + ТипЗначения = ПересечениеТипов(ОписаниеРеквизита.Тип, ОграничениеТипа, ПолноеИмяРеквизита); + Иначе + ТипЗначения = ОписаниеРеквизита.Тип; + КонецЕсли; + + Значение = ЮТТестовыеДанныеСлужебный.Фикция(ТипЗначения, РеквизитыЗаполнения); + ТекущаяЗапись.Вставить(ИмяРеквизита, Значение); + +КонецПроцедуры + +Процедура ФикцияОбязательныхПолей(Контекст) Экспорт + + Реквизиты = Реквизиты(Контекст); + ТекущаяЗапись = ТекущаяЗапись(Контекст); + + Для Каждого Элемент Из Реквизиты Цикл + Реквизит = Элемент.Значение; + Если Реквизит.Обязательный И НЕ ТекущаяЗапись.Свойство(Реквизит.Имя) Тогда + Значение = ЮТТестовыеДанныеСлужебный.Фикция(Реквизит.Тип); + ТекущаяЗапись.Вставить(Реквизит.Имя, Значение); + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +Процедура ТабличнаяЧасть(Контекст, ИмяТабличнойЧасти) Экспорт + + Контекст.ТекущаяТабличнаяЧасть = ИмяТабличнойЧасти; + + Если ИмяТабличнойЧасти <> Неопределено Тогда + Контекст.Данные.Вставить(ИмяТабличнойЧасти, Новый Массив()); + КонецЕсли; + +КонецПроцедуры + +Процедура ДобавитьСтроку(Контекст, ЗначенияРеквизитов) Экспорт + + Запись = Новый Структура(); + ДанныеТабличнойЧасти(Контекст).Добавить(Запись); + + Если ЗначенияРеквизитов <> Неопределено Тогда + УстановитьРеквизиты(Контекст, ЗначенияРеквизитов); + КонецЕсли; + +КонецПроцедуры + +Процедура УстановитьДополнительноеСвойство(Контекст, ИмяСвойства, Значение = Неопределено) Экспорт + + Контекст.ДополнительныеСвойства.Вставить(ИмяСвойства, Значение); + +КонецПроцедуры + +Функция Записать(Контекст, ВернутьОбъект = Ложь, ОбменДаннымиЗагрузка = Ложь) Экспорт + + ПараметрыЗаписи = ЮТОбщий.ПараметрыЗаписи(); + ПараметрыЗаписи.ДополнительныеСвойства = Контекст.ДополнительныеСвойства; + ПараметрыЗаписи.ОбменДаннымиЗагрузка = ОбменДаннымиЗагрузка; + + Ссылка = ЮТТестовыеДанныеСлужебныйВызовСервера.СоздатьЗапись(Контекст.Менеджер, Контекст.Данные, ПараметрыЗаписи, ВернутьОбъект); + + ЮТТестовыеДанныеСлужебный.ДобавитьТестовуюЗапись(Ссылка); + + Возврат Ссылка; + +КонецФункции + +Функция НовыйОбъект(Контекст) Экспорт + + Возврат ЮТТестовыеДанныеСлужебныйВызовСервера.НовыйОбъект(Контекст.Менеджер, Контекст.Данные, Контекст.ДополнительныеСвойства); + +КонецФункции + +Функция Провести(Контекст, ВернутьОбъект = Ложь) Экспорт + + ПараметрыЗаписи = ЮТОбщий.ПараметрыЗаписи(); + ПараметрыЗаписи.ДополнительныеСвойства = Контекст.ДополнительныеСвойства; + ПараметрыЗаписи.РежимЗаписи = РежимЗаписиДокумента.Проведение; + + Ссылка = ЮТТестовыеДанныеСлужебныйВызовСервера.СоздатьЗапись(Контекст.Менеджер, Контекст.Данные, ПараметрыЗаписи, ВернутьОбъект); + + ЮТТестовыеДанныеСлужебный.ДобавитьТестовуюЗапись(Ссылка); + + Возврат Ссылка; + +КонецФункции + +Функция ДанныеСтроки(Контекст) Экспорт + + Если ПустаяСтрока(Контекст.ТекущаяТабличнаяЧасть) Тогда + Возврат Неопределено; + КонецЕсли; + + ДанныеТабличнойЧасти = ДанныеТабличнойЧасти(Контекст); + + Если ДанныеТабличнойЧасти.Количество() Тогда + Возврат ДанныеТабличнойЧасти[ДанныеТабличнойЧасти.ВГраница()]; + Иначе + ВызватьИсключение "Сначала необходимо добавить строку табличной части"; + КонецЕсли; + +КонецФункции + +Функция ДанныеОбъекта(Контекст) Экспорт + + Возврат Контекст.Данные; + +КонецФункции + +// Инициализирует конструктор тестовых данных +// +// Параметры: +// Менеджер - Строка - Имя менеджера. Примеры: Справочники.Товары, Документы.ПриходТоваров +// +// Возвращаемое значение: +// ОбработкаОбъект.ЮТКонструкторТестовыхДанных +Функция Инициализировать(Менеджер) Экспорт + +#Если Сервер Или ТолстыйКлиентОбычноеПриложение Тогда + Конструктор = Обработки.ЮТКонструкторТестовыхДанных.Создать(); +#Иначе + //@skip-check use-non-recommended-method + Конструктор = ПолучитьФорму("Обработка.ЮТКонструкторТестовыхДанных.Форма.КлиентскийКонструктор"); // BSLLS:GetFormMethod-off +#КонецЕсли + + //@skip-check unknown-method-property + Конструктор.Инициализировать(Менеджер); + + Возврат Конструктор; + +КонецФункции + +#КонецОбласти + +#Область СлужебныеПроцедурыИФункции + +// Новый контекст конструктора. +// +// Параметры: +// Менеджер - Произвольный +// +// Возвращаемое значение: +// Структура - Новый контекст конструктора: +// * Менеджер - Произвольный +// * Данные - Структура +// * Метаданные - см. ЮТМетаданные.СтруктураОписанияОбъектаМетаданных +// * ТекущаяТабличнаяЧасть - Строка +// * ДополнительныеСвойства - Структура +Функция НовыйКонтекстКонструктора(Менеджер) Экспорт + + Контекст = Новый Структура("Менеджер, Данные, Метаданные", Менеджер, Новый Структура()); + Контекст.Вставить("Менеджер", Менеджер); + Контекст.Вставить("Данные", Новый Структура()); + Контекст.Вставить("Метаданные", ЮТМетаданные.ОписаниеОбъектаМетаданных(Менеджер)); + Контекст.Вставить("ТекущаяТабличнаяЧасть", ""); + Контекст.Вставить("ДополнительныеСвойства", Новый Структура()); + + //@skip-check constructor-function-return-section + Возврат Контекст; + +КонецФункции + +Функция ДанныеТабличнойЧасти(Контекст) + + Возврат Контекст.Данные[Контекст.ТекущаяТабличнаяЧасть]; + +КонецФункции + +Функция ПересечениеТипов(Знач ОписаниеТипов, Знач ОграничениеТипов, ИмяРеквизита) + + ТипОграничения = ТипЗнч(ОграничениеТипов); + + Если ТипОграничения = Тип("Строка") Тогда + ОграничениеТипов = Новый ОписаниеТипов(ОграничениеТипов); + ТипОграничения = Тип("ОписаниеТипов"); + КонецЕсли; + + Если ТипОграничения = Тип("Тип") И ОписаниеТипов.СодержитТип(ОграничениеТипов) И ОграничениеТипов <> Тип("Неопределено") Тогда + Результат = ЮТКоллекции.ЗначениеВМассиве(ОграничениеТипов); + ИначеЕсли ТипОграничения = Тип("ОписаниеТипов") Тогда + Результат = ЮТКоллекции.ПересечениеМассивов(ОписаниеТипов.Типы(), ОграничениеТипов.Типы()); + Иначе + Результат = Неопределено; + КонецЕсли; + + Если НЕ ЗначениеЗаполнено(Результат) Тогда + + Сообщение = СтрШаблон("Исправьте ограничение типов для реквизита `%1` (`%2`), оно не входит в множество типов реквизита (`%3`)", + ИмяРеквизита, + ОграничениеТипов, + ОписаниеТипов); + ВызватьИсключение Сообщение; + + КонецЕсли; + + Возврат Новый ОписаниеТипов(Результат, + ОписаниеТипов.КвалификаторыЧисла, + ОписаниеТипов.КвалификаторыСтроки, + ОписаниеТипов.КвалификаторыДаты, + ОписаниеТипов.КвалификаторыДвоичныхДанных); + +КонецФункции + +Функция Реквизиты(Контекст) + + Если ЗначениеЗаполнено(Контекст.ТекущаяТабличнаяЧасть) Тогда + Возврат Контекст.Метаданные.ТабличныеЧасти[Контекст.ТекущаяТабличнаяЧасть]; + Иначе + Возврат Контекст.Метаданные.Реквизиты; + КонецЕсли; + +КонецФункции + +Функция ОписаниеРеквизита(Контекст, ИмяРеквизита) + + Реквизиты = Реквизиты(Контекст); + + Если НЕ Реквизиты.Свойство(ИмяРеквизита) Тогда + ИмяОсновнойТаблицы = ЮТМетаданные.НормализованноеИмяТаблицы(Контекст.Метаданные); + Если ЗначениеЗаполнено(Контекст.ТекущаяТабличнаяЧасть) Тогда + Пояснение = СтрШаблон("Табличная часть `%1.%2` не содержит реквизит `%3`", ИмяОсновнойТаблицы, Контекст.ТекущаяТабличнаяЧасть, ИмяРеквизита); + Иначе + Пояснение = СтрШаблон("`%1` не содержит реквизит `%2`", ИмяОсновнойТаблицы, ИмяРеквизита); + КонецЕсли; + + ВызватьИсключение Пояснение; + КонецЕсли; + + Возврат Реквизиты[ИмяРеквизита]; + +КонецФункции + +Функция ТекущаяЗапись(Контекст) + + Если ЗначениеЗаполнено(Контекст.ТекущаяТабличнаяЧасть) Тогда + Возврат ДанныеСтроки(Контекст); + Иначе + Возврат Контекст.Данные; + КонецЕсли; + +КонецФункции + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТКонтекстСлужебный.xml b/src/cfe/YAXUnit/CommonModules/ЮТКонтекстСлужебный.xml new file mode 100644 index 0000000..2c0eada --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТКонтекстСлужебный.xml @@ -0,0 +1,23 @@ + + + + + ЮТКонтекстСлужебный + + + ru + Контекст тестового движка + + + + false + true + true + false + true + false + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТКонтекстСлужебный/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТКонтекстСлужебный/Ext/Module.bsl new file mode 100644 index 0000000..d60983b --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТКонтекстСлужебный/Ext/Module.bsl @@ -0,0 +1,339 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область СлужебныйПрограммныйИнтерфейс + +// ИнициализироватьКонтекст +// Выполняет начальную настройку для работы с хранимым контекстом +Процедура ИнициализироватьКонтекст() Экспорт + +#Если НЕ Клиент Тогда + ВызватьИсключение "Метод `ИнициализироватьКонтекст` должен вызываться только с клиента"; +#Иначе + ЮТКонтекстСлужебныйКлиент.ИнициализироватьКонтекст(); + ЮТКонтекстСлужебныйВызовСервера.ИнициализироватьКонтекст(); + ОбновитьПовторноИспользуемыеЗначения(); +#КонецЕсли + +КонецПроцедуры + +// ДанныеКонтекста +// Возвращает хранимые данные контекста. +// Существует отдельно контекст сервера, отдельно клиента, эти контексты никак не связаны и никак не синхронизируются +// Возвращаемое значение: +// Структура - Данные контекста +Функция ДанныеКонтекста() Экспорт + +#Если Клиент Тогда + Возврат ЮТКонтекстСлужебныйКлиент.ДанныеКонтекста(); +#Иначе + //@skip-check constructor-function-return-section + Возврат ЮТКонтекстСлужебныйВызовСервера.ДанныеКонтекста(); +#КонецЕсли + +КонецФункции + +// ЗначениеКонтекста +// Возвращает значение вложенного контекста, вложенного реквизита контекста +// Параметры: +// ИмяРеквизита - Строка - Имя реквизита/вложенного контекста +// ПолучитьССервера - Булево - Получить значение из серверного контекста +// Возвращаемое значение: +// - Структура - Значение реквизита/вложенного контекста +// - Неопределено +Функция ЗначениеКонтекста(ИмяРеквизита, ПолучитьССервера = Ложь) Экспорт + +#Если Клиент Тогда + Если ПолучитьССервера Тогда + //@skip-check constructor-function-return-section + Возврат ЮТКонтекстСлужебныйВызовСервера.ЗначениеКонтекста(ИмяРеквизита); + КонецЕсли; +#КонецЕсли + + Объект = ДанныеКонтекста(); + + Если Объект = Неопределено Тогда + Возврат Неопределено; + КонецЕсли; + + Ключи = СтрРазделить(ИмяРеквизита, "."); + Для Инд = 0 По Ключи.Количество() - 2 Цикл + Объект = Объект[Ключи[Инд]]; + КонецЦикла; + + //@skip-check constructor-function-return-section + Возврат ЮТКоллекции.ЗначениеСтруктуры(Объект, Ключи[Ключи.ВГраница()]); + +КонецФункции + +// УстановитьЗначениеКонтекста +// Устанавливает значение вложенного контекста, вложенного реквизита контекста +// +// Параметры: +// ИмяРеквизита - Строка - Имя реквизита/вложенного контекста +// Значение - Произвольный - Новое значение реквизита/вложенного контекста +// УстановитьНаСервер - Булево - Установить также на сервер +Процедура УстановитьЗначениеКонтекста(Знач ИмяРеквизита, Знач Значение, Знач УстановитьНаСервер = Ложь) Экспорт + + ДанныеКонтекста = ДанныеКонтекста(); + + Объект = ДанныеКонтекста; + Ключи = СтрРазделить(ИмяРеквизита, "."); + Для Инд = 0 По Ключи.Количество() - 2 Цикл + Объект = Объект[Ключи[Инд]]; + КонецЦикла; + + Объект.Вставить(Ключи[Ключи.ВГраница()], Значение); + +#Если НЕ Сервер Тогда + Если УстановитьНаСервер Тогда + ЮТКонтекстСлужебныйВызовСервера.УстановитьЗначениеКонтекста(ИмяРеквизита, Значение); + КонецЕсли; +#КонецЕсли + +КонецПроцедуры + +// КонтекстТеста +// Возвращает структуру, в которой можно хранить данные используемые в тесте +// Данные живут в рамках одного теста, но доступны в обработчиках событий `ПередКаждымТестом` и `ПослеКаждогоТеста` +// Например, в контекст можно помещать создаваемые данные, что бы освободить/удалить их в обработчике `ПослеКаждогоТеста` +// +// Параметры: +// ПолучитьССервера - Булево - Получить контекст с сервера +// +// Возвращаемое значение: +// - Структура - Контекст теста +// - Неопределено - Если метод вызывается за рамками теста +Функция КонтекстТеста(ПолучитьССервера = Ложь) Экспорт + + //@skip-check constructor-function-return-section + Возврат ЗначениеКонтекста(ИмяКонтекстаТеста(), ПолучитьССервера); + +КонецФункции + +// КонтекстНабора +// Возвращает структуру, в которой можно хранить данные используемые в тестах набора +// Данные живут в рамках одного набора тестов (данные между клиентом и сервером не синхронизируются) +// Доступны в каждом тесте набора и в обработчиках событий +// + `ПередТестовымНабором` +// + `ПослеТестовогоНабора` +// + `ПередКаждымТестом` +// + `ПослеКаждогоТеста` +// Например, в контекст можно помещать создаваемые данные, что бы освободить/удалить их в обработчике `ПослеКаждогоТеста` +// Возвращаемое значение: +// - Структура - Контекст набора тестов +// - Неопределено - Если метод вызывается за рамками тестового набора +Функция КонтекстНабора() Экспорт + + //@skip-check constructor-function-return-section + Возврат ЗначениеКонтекста(ИмяКонтекстаНабораТестов()); + +КонецФункции + +// КонтекстМодуля +// Возвращает структуру, в которой можно хранить данные используемые в тестах модуля +// Данные живут в рамках одного тестового модуля (данные между клиентом и сервером не синхронизируются) +// Доступны в каждом тесте модуля и в обработчиках событий +// Например, в контекст можно помещать создаваемые данные, что бы освободить/удалить их в обработчике `ПослеВсехТестов` +// Возвращаемое значение: +// - Структура - Контекст тестового модуля +// - Неопределено - Если метод вызывается за рамками тестового модуля +Функция КонтекстМодуля() Экспорт + + //@skip-check constructor-function-return-section + Возврат ЗначениеКонтекста(ИмяКонтекстаМодуля()); + +КонецФункции + +Функция ГлобальныеНастройкиВыполнения() Экспорт + + Возврат ЗначениеКонтекста(ИмяГлобальныеНастройкиВыполнения()); + +КонецФункции + +// КонтекстПроверки +// Возвращает служебный контекста, данные выполняемой проверки +// Возвращаемое значение: +// Неопределено, Структура - Контекст проверки +Функция КонтекстПроверки() Экспорт + + //@skip-check constructor-function-return-section + Возврат ЗначениеКонтекста(ИмяКонтекстаУтверждений()); + +КонецФункции + +// КонтекстЧитателя +// Возвращает служебный контекста, данные необходимые на этапе загрузки тестов +// Возвращаемое значение: +// Неопределено, Структура - Контекст проверки +Функция КонтекстЧитателя() Экспорт + + //@skip-check constructor-function-return-section + Возврат ЗначениеКонтекста(ИмяКонтекстаЧитателя()); + +КонецФункции + +// КонтекстЧитателя +// Возвращает служебный контекста, данные используемые исполнителем тестов +// Возвращаемое значение: +// см. ЮТФабрикаСлужебный.НовыйКонтекстИсполнения +Функция КонтекстИсполнения() Экспорт + + //@skip-check constructor-function-return-section + Возврат ЗначениеКонтекста(ИмяКонтекстаИсполнения()); + +КонецФункции + +// Контекст исполнения текущего уровня. +// +// Возвращаемое значение: +// - Неопределено +// - См. ЮТФабрикаСлужебный.ОписаниеТестовогоМодуля +// - См. ЮТФабрикаСлужебный.ОписаниеИсполняемогоНабораТестов +// - См. ЮТФабрикаСлужебный.ОписаниеИсполняемогоТеста +Функция КонтекстИсполненияТекущегоУровня() Экспорт + + Уровни = ЮТФабрика.УровниИсполнения(); + КонтекстИсполнения = КонтекстИсполнения(); + + Если КонтекстИсполнения.Уровень = Уровни.Модуль Тогда + + Возврат КонтекстИсполнения.Модуль; + + ИначеЕсли КонтекстИсполнения.Уровень = Уровни.НаборТестов Тогда + + Возврат КонтекстИсполнения.Набор; + + ИначеЕсли КонтекстИсполнения.Уровень = Уровни.Тест Тогда + + Возврат КонтекстИсполнения.Тест; + + Иначе + + Возврат Неопределено; + + КонецЕсли; + +КонецФункции + +Функция ОписаниеКонтекста() Экспорт + + Описание = Новый Структура; + + Возврат Описание; + +КонецФункции + +Процедура УстановитьКонтекстУтверждений(Знач ДанныеКонтекста) Экспорт + + УстановитьЗначениеКонтекста(ИмяКонтекстаУтверждений(), ДанныеКонтекста); + +КонецПроцедуры + +Процедура УстановитьКонтекстНабораТестов() Экспорт + + УстановитьЗначениеКонтекста(ИмяКонтекстаНабораТестов(), Новый Структура); + +КонецПроцедуры + +Процедура УстановитьКонтекстМодуля() Экспорт + + УстановитьЗначениеКонтекста(ИмяКонтекстаМодуля(), Новый Структура); + +КонецПроцедуры + +Процедура УстановитьКонтекстТеста() Экспорт + + УстановитьЗначениеКонтекста(ИмяКонтекстаТеста(), Новый Структура); + +КонецПроцедуры + +Процедура УстановитьКонтекстЧитателя(Знач ДанныеКонтекста) Экспорт + + УстановитьЗначениеКонтекста(ИмяКонтекстаЧитателя(), ДанныеКонтекста, Истина); + +КонецПроцедуры + +Процедура УстановитьКонтекстИсполнения(Знач ДанныеКонтекста) Экспорт + + УстановитьЗначениеКонтекста(ИмяКонтекстаИсполнения(), ДанныеКонтекста, Истина); + +КонецПроцедуры + +Процедура УстановитьГлобальныеНастройкиВыполнения(Знач Настройки) Экспорт + + УстановитьЗначениеКонтекста(ИмяГлобальныеНастройкиВыполнения(), Настройки, Истина); + +КонецПроцедуры + +Процедура УдалитьКонтекст() Экспорт + +#Если Клиент Тогда + ЮТКонтекстСлужебныйКлиент.УдалитьКонтекст(); +#КонецЕсли + ЮТКонтекстСлужебныйВызовСервера.УдалитьКонтекст(); + +КонецПроцедуры + +#КонецОбласти + +#Область СлужебныеПроцедурыИФункции + +Функция ИмяКонтекстаУтверждений() + + Возврат "КонтекстУтверждения"; + +КонецФункции + +Функция ИмяКонтекстаНабораТестов() + + Возврат "КонтекстНабора"; + +КонецФункции + +Функция ИмяКонтекстаМодуля() + + Возврат "КонтекстМодуля"; + +КонецФункции + +Функция ИмяКонтекстаТеста() + + Возврат "КонтекстТеста"; + +КонецФункции + +Функция ИмяКонтекстаЧитателя() + + Возврат "КонтекстЧитателя"; + +КонецФункции + +Функция ИмяГлобальныеНастройкиВыполнения() + + Возврат "ГлобальныеНастройкиВыполнения"; + +КонецФункции + +Функция ИмяКонтекстаИсполнения() + + Возврат "КонтекстИсполнения"; + +КонецФункции + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТКонтекстСлужебныйВызовСервера.xml b/src/cfe/YAXUnit/CommonModules/ЮТКонтекстСлужебныйВызовСервера.xml new file mode 100644 index 0000000..b1787ec --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТКонтекстСлужебныйВызовСервера.xml @@ -0,0 +1,23 @@ + + + + + ЮТКонтекстСлужебныйВызовСервера + + + ru + Контекст (сервер) + + + + false + false + true + false + false + true + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТКонтекстСлужебныйВызовСервера/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТКонтекстСлужебныйВызовСервера/Ext/Module.bsl new file mode 100644 index 0000000..bbd92c4 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТКонтекстСлужебныйВызовСервера/Ext/Module.bsl @@ -0,0 +1,95 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область СлужебныйПрограммныйИнтерфейс + +Процедура ИнициализироватьКонтекст() Экспорт + + Контекст = ЮТКонтекстСлужебный.ОписаниеКонтекста(); + АдресХранилища = ПоместитьВоВременноеХранилище(Контекст, Новый УникальныйИдентификатор()); + ХранилищеОбщихНастроек.Сохранить(КлючНастроекКонтекста(), "АдресХранилища", АдресХранилища); + + ОбновитьПовторноИспользуемыеЗначения(); + +КонецПроцедуры + +Функция ДанныеКонтекста() Экспорт + + Адрес = АдресСерверногоКонтекста(); + + Если ЭтоАдресВременногоХранилища(Адрес) Тогда + + Возврат ПолучитьИзВременногоХранилища(АдресСерверногоКонтекста()); + + КонецЕсли; + +КонецФункции + +// УстановитьЗначениеКонтекста +// Устанавливает значение вложенного контекста, вложенного реквизита контекста +// +// Параметры: +// ИмяРеквизита - Строка - Имя реквизита/вложенного контекста +// Значение - Произвольный - Новое значение реквизита/вложенного контекста +Процедура УстановитьЗначениеКонтекста(Знач ИмяРеквизита, Знач Значение) Экспорт + + ЮТКонтекстСлужебный.УстановитьЗначениеКонтекста(ИмяРеквизита, Значение); + +КонецПроцедуры + +Функция ЗначениеКонтекста(Знач ИмяРеквизита) Экспорт + + Возврат ЮТКонтекстСлужебный.ЗначениеКонтекста(ИмяРеквизита); + +КонецФункции + +Функция КлючНастроекКонтекста() Экспорт + + Возврат СтрШаблон("ЮТ%1.Контекста", НомерСеансаИнформационнойБазы()); + +КонецФункции + +Функция АдресСерверногоКонтекста(Кэшировать = Истина) Экспорт + + Если Кэшировать Тогда + + Возврат ЮТСлужебныйПовторногоИспользования.АдресСерверногоКонтекста(); + + Иначе + + Возврат ХранилищеОбщихНастроек.Загрузить(КлючНастроекКонтекста(), "АдресХранилища"); + + КонецЕсли; + +КонецФункции + +Процедура УдалитьКонтекст() Экспорт + + Адрес = АдресСерверногоКонтекста(); + + Если ЭтоАдресВременногоХранилища(Адрес) Тогда + УдалитьИзВременногоХранилища(Адрес); + УстановитьПривилегированныйРежим(Истина); + ХранилищеОбщихНастроек.Удалить(КлючНастроекКонтекста(), "АдресХранилища", Неопределено); + УстановитьПривилегированныйРежим(Ложь); + ОбновитьПовторноИспользуемыеЗначения(); + КонецЕсли; + +КонецПроцедуры + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТКонтекстСлужебныйКлиент.xml b/src/cfe/YAXUnit/CommonModules/ЮТКонтекстСлужебныйКлиент.xml new file mode 100644 index 0000000..1b404ea --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТКонтекстСлужебныйКлиент.xml @@ -0,0 +1,23 @@ + + + + + ЮТКонтекстСлужебныйКлиент + + + ru + Контекст (клиент) + + + + false + true + false + false + true + false + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТКонтекстСлужебныйКлиент/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТКонтекстСлужебныйКлиент/Ext/Module.bsl new file mode 100644 index 0000000..a20cef8 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТКонтекстСлужебныйКлиент/Ext/Module.bsl @@ -0,0 +1,39 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область СлужебныйПрограммныйИнтерфейс + +Процедура ИнициализироватьКонтекст() Экспорт + + ЮТДанныеКонтекста = ЮТКонтекстСлужебный.ОписаниеКонтекста(); // BSLLS:UnusedLocalVariable-off + +КонецПроцедуры + +Функция ДанныеКонтекста() Экспорт + + Возврат ЮТДанныеКонтекста; + +КонецФункции + +Процедура УдалитьКонтекст() Экспорт + + ЮТДанныеКонтекста = Неопределено; // BSLLS:UnusedLocalVariable-off + +КонецПроцедуры + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТКонтекстТеста.xml b/src/cfe/YAXUnit/CommonModules/ЮТКонтекстТеста.xml new file mode 100644 index 0000000..2c9decb --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТКонтекстТеста.xml @@ -0,0 +1,23 @@ + + + + + ЮТКонтекстТеста + + + ru + Контекст теста + + + + false + true + true + false + true + false + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТКонтекстТеста/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТКонтекстТеста/Ext/Module.bsl new file mode 100644 index 0000000..d3659f7 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТКонтекстТеста/Ext/Module.bsl @@ -0,0 +1,126 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область ПрограммныйИнтерфейс + +// Возвращает значение контекста +// +// Параметры: +// ИмяЗначения - Строка +// +// Возвращаемое значение: +// Произвольный - Сохраненное в контексте значение +Функция Значение(ИмяЗначения) Экспорт + + Уровень = ЮТКонтекстСлужебный.КонтекстИсполнения().Уровень; + Уровни = ЮТФабрика.УровниИсполнения(); + + КонтекстТеста = ЮТКонтекстСлужебный.КонтекстТеста(); + Если Уровень = Уровни.Тест И КонтекстТеста <> Неопределено И КонтекстТеста.Свойство(ИмяЗначения) Тогда + + Возврат КонтекстТеста[ИмяЗначения]; + + КонецЕсли; + + КонтекстНабора = ЮТКонтекстСлужебный.КонтекстНабора(); + Если (Уровень = Уровни.НаборТестов ИЛИ Уровень = Уровни.Тест) + И КонтекстНабора <> Неопределено И КонтекстНабора.Свойство(ИмяЗначения) Тогда + + Возврат КонтекстНабора[ИмяЗначения]; + + КонецЕсли; + + КонтекстМодуля = ЮТКонтекстСлужебный.КонтекстМодуля(); + Если (Уровень = Уровни.Модуль ИЛИ Уровень = Уровни.Тест ИЛИ Уровень = Уровни.НаборТестов) + И КонтекстМодуля <> Неопределено И КонтекстМодуля.Свойство(ИмяЗначения) Тогда + + Возврат КонтекстМодуля[ИмяЗначения]; + + Иначе + + Возврат Неопределено; + + КонецЕсли; + +КонецФункции + +// Установить значение. +// Устанавливает значение в контекст тестов. +// Установка происходит в соответствии с уровнем исполнения +// Параметры: +// ИмяЗначения - Строка +// Значение - Произвольный +Процедура УстановитьЗначение(ИмяЗначения, Значение) Экспорт + + Уровень = ЮТКонтекстСлужебный.КонтекстИсполнения().Уровень; + Уровни = ЮТФабрика.УровниИсполнения(); + + Контекст = ТекущийКонтекст(); + + Если Контекст = Неопределено Тогда + + Если Уровень = Уровни.Тест Тогда + ЮТКонтекстСлужебный.УстановитьКонтекстТеста(); + ИначеЕсли Уровень = Уровни.НаборТестов Тогда + ЮТКонтекстСлужебный.УстановитьКонтекстНабораТестов(); + ИначеЕсли Уровень = Уровни.Модуль Тогда + ЮТКонтекстСлужебный.УстановитьКонтекстМодуля(); + Иначе + ВызватьИсключение СтрШаблон("Неизвестный уровень исполнения `%1`", Уровень); + КонецЕсли; + + Контекст = ТекущийКонтекст(); + + КонецЕсли; + + Контекст.Вставить(ИмяЗначения, Значение); + +КонецПроцедуры + +// Текущий контекст исполнения теста +// +// Возвращаемое значение: +// Неопределено, Структура, Произвольный - Текущий контекст +Функция ТекущийКонтекст() Экспорт + + Уровень = ЮТКонтекстСлужебный.КонтекстИсполнения().Уровень; + Уровни = ЮТФабрика.УровниИсполнения(); + + Если Уровень = Уровни.Тест Тогда + + Контекст = ЮТКонтекстСлужебный.КонтекстТеста(); + + ИначеЕсли Уровень = Уровни.НаборТестов Тогда + + Контекст = ЮТКонтекстСлужебный.КонтекстНабора(); + + ИначеЕсли Уровень = Уровни.Модуль Тогда + + Контекст = ЮТКонтекстСлужебный.КонтекстМодуля(); + + Иначе + + Контекст = Неопределено; + + КонецЕсли; + + Возврат Контекст; + +КонецФункции + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТЛогИсполненияТестаСлужебный.xml b/src/cfe/YAXUnit/CommonModules/ЮТЛогИсполненияТестаСлужебный.xml new file mode 100644 index 0000000..37a3af3 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТЛогИсполненияТестаСлужебный.xml @@ -0,0 +1,23 @@ + + + + + ЮТЛогИсполненияТестаСлужебный + + + ru + Лог исполнения теста служебный + + + + false + true + true + false + true + false + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТЛогИсполненияТестаСлужебный/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТЛогИсполненияТестаСлужебный/Ext/Module.bsl new file mode 100644 index 0000000..a329dfe --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТЛогИсполненияТестаСлужебный/Ext/Module.bsl @@ -0,0 +1,84 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область СлужебныйПрограммныйИнтерфейс + +Процедура ДобавитьСообщение(Текст) Экспорт + + ДобавитьЗапись("[INF] " + Текст); + +КонецПроцедуры + +Процедура ДобавитьОшибку(Текст) Экспорт + + ДобавитьЗапись("[ERR] " + Текст); + +КонецПроцедуры + +Процедура ДобавитьПредупреждение(Текст) Экспорт + + ДобавитьЗапись("[WRN] " + Текст); + +КонецПроцедуры + +Функция Записи() Экспорт + + Если ЮТест.КонтекстТеста() = Неопределено Тогда + Возврат Неопределено; + КонецЕсли; + + Лог = ЮТКоллекции.ЗначениеСтруктуры(ЮТест.КонтекстТеста(), "Лог"); +#Если Сервер Тогда + Возврат Лог; +#Иначе + СерверныйКонтекст = ЮТКонтекстСлужебный.КонтекстТеста(Истина); + СерверныйЛог = ЮТКоллекции.ЗначениеСтруктуры(СерверныйКонтекст, "Лог"); + + Если Лог = Неопределено Тогда + Лог = СерверныйЛог; + ИначеЕсли СерверныйЛог <> Неопределено Тогда + ЮТКоллекции.ДополнитьМассив(Лог, СерверныйЛог); + КонецЕсли; +#КонецЕсли + + Возврат Лог; + +КонецФункции + +#КонецОбласти + +#Область СлужебныеПроцедурыИФункции + +Процедура ДобавитьЗапись(Текст) + + Если ЮТест.КонтекстТеста() = Неопределено Тогда + Возврат; + КонецЕсли; + + Ошибки = Неопределено; + + Если НЕ ЮТест.КонтекстТеста().Свойство("Лог", Ошибки) Тогда + Ошибки = Новый Массив(); + ЮТест.КонтекстТеста().Вставить("Лог", Ошибки); + КонецЕсли; + + Ошибки.Добавить(Текст); + +КонецПроцедуры + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТЛогирование.xml b/src/cfe/YAXUnit/CommonModules/ЮТЛогирование.xml new file mode 100644 index 0000000..dd00493 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТЛогирование.xml @@ -0,0 +1,23 @@ + + + + + ЮТЛогирование + + + ru + Логирование + + + + false + true + true + false + true + false + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТЛогирование/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТЛогирование/Ext/Module.bsl new file mode 100644 index 0000000..88588c3 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТЛогирование/Ext/Module.bsl @@ -0,0 +1,71 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область ПрограммныйИнтерфейс + +// Выводит отладочное сообщение +// +// Параметры: +// Сообщение - Строка - Сообщение +Процедура Отладка(Сообщение) Экспорт + + ЮТЛогированиеСлужебный.Записать("DBG", Сообщение, 0); + +КонецПроцедуры + +// Выводит информационное сообщение +// +// Параметры: +// Сообщение - Строка - Сообщение +Процедура Информация(Сообщение) Экспорт + + ЮТЛогированиеСлужебный.Записать("INF", Сообщение, 10); + +КонецПроцедуры + +// Выводит предупреждение +// +// Параметры: +// Сообщение - Строка - Сообщение +Процедура Предостережение(Сообщение) Экспорт + + ЮТЛогированиеСлужебный.Записать("WRN", Сообщение, 20); + +КонецПроцедуры + +// Выводит сообщение об ошибке +// +// Параметры: +// Сообщение - Строка - Сообщение +Процедура Ошибка(Сообщение) Экспорт + + ЮТЛогированиеСлужебный.Записать("ERR", Сообщение, 99); + +КонецПроцедуры + +#КонецОбласти + +#Область СлужебныйПрограммныйИнтерфейс + +Функция УровниЛога() Экспорт + + Возврат Новый ФиксированнаяСтруктура("Отладка, Информация, Предупреждение, Ошибка", "debug", "info", "warning", "error"); + +КонецФункции + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТЛогированиеСлужебный.xml b/src/cfe/YAXUnit/CommonModules/ЮТЛогированиеСлужебный.xml new file mode 100644 index 0000000..273c9a1 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТЛогированиеСлужебный.xml @@ -0,0 +1,23 @@ + + + + + ЮТЛогированиеСлужебный + + + ru + Логирование служебный + + + + false + true + true + false + true + false + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТЛогированиеСлужебный/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТЛогированиеСлужебный/Ext/Module.bsl new file mode 100644 index 0000000..a53c92e --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТЛогированиеСлужебный/Ext/Module.bsl @@ -0,0 +1,395 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область СлужебныйПрограммныйИнтерфейс + +Процедура Записать(УровеньЛога, Сообщение, Приоритет) Экспорт + + Контекст = Контекст(); + Если НЕ ЛогированиеВключено(Контекст, Приоритет) Тогда + Возврат; + КонецЕсли; + +#Если Клиент Тогда + КонтекстИсполнения = "Клиент"; +#Иначе + КонтекстИсполнения = "Сервер"; +#КонецЕсли + Текст = СтрШаблон("%1 [%2][%3]: %4", ЮТОбщий.ПредставлениеУниверсальнойДата(), КонтекстИсполнения, УровеньЛога, Сообщение); +#Если Клиент Тогда + ЗаписатьСообщения(Контекст, ЮТКоллекции.ЗначениеВМассиве(Текст)); +#Иначе + Если Контекст.ФайлЛогаДоступенНаСервере Тогда + ЗаписатьСообщения(Контекст, ЮТКоллекции.ЗначениеВМассиве(Текст)); + Иначе + Контекст.НакопленныеЗаписи.Добавить(Текст); + КонецЕсли; +#КонецЕсли + +КонецПроцедуры + +Процедура ВывестиСерверныеСообщения() Экспорт + +#Если Клиент Тогда + Контекст = Контекст(); + Если Контекст = Неопределено ИЛИ НЕ Контекст.Включено ИЛИ Контекст.ФайлЛогаДоступенНаСервере Тогда + Возврат; + КонецЕсли; + + Сообщения = ЮТЛогированиеСлужебныйВызовСервера.НакопленныеСообщенияЛогирования(Истина); + ЗаписатьСообщения(Контекст, Сообщения); +#Иначе + ВызватьИсключение ЮТИсключения.МетодНеДоступен("ВывестиСерверныеСообщения"); +#КонецЕсли + +КонецПроцедуры + +Функция НакопленныеСообщенияЛогирования(Очистить = Ложь) Экспорт + + Контекст = Контекст(); + + Сообщения = Контекст.НакопленныеЗаписи; + + Если Очистить Тогда + Контекст.НакопленныеЗаписи = Новый Массив(); + КонецЕсли; + + Возврат Сообщения; + +КонецФункции + +#Область ОбработчикиСобытий + +// Инициализация. +// +// Параметры: +// ПараметрыЗапуска - см. ЮТФабрика.ПараметрыЗапуска +Процедура Инициализация(ПараметрыЗапуска) Экспорт + + УровниЛога = ЮТЛогирование.УровниЛога(); + + ДанныеКонтекста = НовыйДанныеКонтекста(); + ДанныеКонтекста.ФайлЛога = ЮТКоллекции.ЗначениеСтруктуры(ПараметрыЗапуска.logging, "file"); + ДанныеКонтекста.ВыводВКонсоль = ЮТКоллекции.ЗначениеСтруктуры(ПараметрыЗапуска.logging, "console", Ложь); + ДанныеКонтекста.Включено = ЮТКоллекции.ЗначениеСтруктуры(ПараметрыЗапуска.logging, "enable", Неопределено); + УровеньЛога = ЮТКоллекции.ЗначениеСтруктуры(ПараметрыЗапуска.logging, "level", УровниЛога.Отладка); + + Если ДанныеКонтекста.Включено = Неопределено Тогда + ДанныеКонтекста.Включено = ДанныеКонтекста.ВыводВКонсоль ИЛИ ЗначениеЗаполнено(ДанныеКонтекста.ФайлЛога); + КонецЕсли; + + Если НЕ ДанныеКонтекста.Включено Тогда + ЮТКонтекстСлужебный.УстановитьЗначениеКонтекста(ИмяКонтекстаЛогирования(), ДанныеКонтекста, Истина); + Возврат; + КонецЕсли; + + Если СтрСравнить(УровеньЛога, УровниЛога.Ошибка) = 0 Тогда + ДанныеКонтекста.УровеньЛога = 99; + ИначеЕсли СтрСравнить(УровеньЛога, УровниЛога.Информация) = 0 Тогда + ДанныеКонтекста.УровеньЛога = 10; + ИначеЕсли СтрСравнить(УровеньЛога, УровниЛога.Предупреждение) = 0 Тогда + ДанныеКонтекста.УровеньЛога = 20; + Иначе + ДанныеКонтекста.УровеньЛога = 0; + КонецЕсли; + + ЗначениеПроверки = Строка(Новый УникальныйИдентификатор()); + ЗаписатьСообщения(ДанныеКонтекста, ЮТКоллекции.ЗначениеВМассиве(ЗначениеПроверки), Ложь); + + ДанныеКонтекста.ФайлЛогаДоступенНаСервере = ЮТЛогированиеСлужебныйВызовСервера.ФайлЛогаДоступенНаСервере(ДанныеКонтекста.ФайлЛога, ЗначениеПроверки); + + ЮТКонтекстСлужебный.УстановитьЗначениеКонтекста(ИмяКонтекстаЛогирования(), ДанныеКонтекста, Истина); + + Разделитель = "------------------------------------------------------"; + ЗаписатьСообщения(ДанныеКонтекста, ЮТКоллекции.ЗначениеВМассиве(Разделитель), Ложь); + + ЮТЛогирование.Информация("Старт"); + +КонецПроцедуры + +// Обработка события "ПередЧтениеСценариев" +Процедура ПередЧтениеСценариев() Экспорт + + ЮТЛогирование.Информация("Загрузка сценариев"); + +КонецПроцедуры + +// Перед чтением сценариев модуля. +// +// Параметры: +// МетаданныеМодуля - см. ЮТФабрикаСлужебный.ОписаниеМодуля +// ИсполняемыеСценарии - см. ЮТТесты.СценарииМодуля +Процедура ПередЧтениемСценариевМодуля(МетаданныеМодуля, ИсполняемыеСценарии) Экспорт + + ЮТЛогирование.Информация(СтрШаблон("Загрузка сценариев модуля `%1`", МетаданныеМодуля.Имя)); + +КонецПроцедуры + +// Перед чтением сценариев модуля. +// +// Параметры: +// МетаданныеМодуля - см. ЮТФабрикаСлужебный.ОписаниеМодуля +// ИсполняемыеСценарии - см. ЮТТесты.СценарииМодуля +Процедура ПослеЧтенияСценариевМодуля(МетаданныеМодуля, ИсполняемыеСценарии) Экспорт + + ЮТЛогирование.Информация(СтрШаблон("Загрузка сценариев модуля завершена `%1`", МетаданныеМодуля.Имя)); + +КонецПроцедуры + +// Обработка события "ПослеЧтенияСценариев" +// Параметры: +// Сценарии - Массив из см. ЮТФабрикаСлужебный.ОписаниеТестовогоМодуля - Набор описаний тестовых модулей, которые содержат информацию о запускаемых тестах +Процедура ПослеЧтенияСценариев(Сценарии) Экспорт + + ЮТЛогирование.Информация("Загрузка сценариев завершена."); + +КонецПроцедуры + +// Обработка события "ПослеФормированияИсполняемыхНаборовТестов" +// Параметры: +// ИсполняемыеТестовыеМодули - Массив из см. ЮТФабрикаСлужебный.ОписаниеИсполняемогоТестовогоМодуля - Набор исполняемых наборов +Процедура ПослеФормированияИсполняемыхНаборовТестов(ИсполняемыеТестовыеМодули) Экспорт + + Количество = 0; + + Для Каждого ТестовыйМодуль Из ИсполняемыеТестовыеМодули Цикл + + Для Каждого Набор Из ТестовыйМодуль.НаборыТестов Цикл + + Если Набор.Выполнять Тогда + ЮТОбщий.Инкремент(Количество, Набор.Тесты.Количество()); + КонецЕсли; + + КонецЦикла; + + КонецЦикла; + + ЮТКонтекстСлужебный.УстановитьЗначениеКонтекста(ИмяКонтекстаЛогирования() + ".ОбщееКоличествоТестов", Количество, Истина); + +КонецПроцедуры + +// Перед всеми тестами. +// +// Параметры: +// ОписаниеСобытия - см. ЮТФабрикаСлужебный.ОписаниеСобытияИсполненияТестов +Процедура ПередВсемиТестами(ОписаниеСобытия) Экспорт + +#Если Клиент Тогда + Контекст = Контекст(); + ПрогрессКлиент = Контекст.КоличествоВыполненныхТестов; + ПрогрессСервер = ЮТКонтекстСлужебный.ЗначениеКонтекста(ИмяКонтекстаЛогирования() + ".КоличествоВыполненныхТестов", Истина); + + Если ПрогрессКлиент < ПрогрессСервер Тогда + Контекст.КоличествоВыполненныхТестов = ПрогрессСервер; + КонецЕсли; +#КонецЕсли + ЮТЛогирование.Информация(СтрШаблон("Запуск тестов модуля `%1`", ОписаниеСобытия.Модуль.МетаданныеМодуля.ПолноеИмя)); + +КонецПроцедуры + +// Перед тестовым набором. +// +// Параметры: +// ОписаниеСобытия - см. ЮТФабрикаСлужебный.ОписаниеСобытияИсполненияТестов +Процедура ПередТестовымНабором(ОписаниеСобытия) Экспорт + + ЮТЛогирование.Информация(СтрШаблон("Запуск тестов набора `%1`", ОписаниеСобытия.Набор.Имя)); + +КонецПроцедуры + +// Перед каждым тестом. +// +// Параметры: +// ОписаниеСобытия - см. ЮТФабрикаСлужебный.ОписаниеСобытияИсполненияТестов +Процедура ПередКаждымТестом(ОписаниеСобытия) Экспорт + + ЮТЛогирование.Информация(СтрШаблон("Запуск теста `%1`", ОписаниеСобытия.Тест.Имя)); + +КонецПроцедуры + +// Перед каждым тестом. +// +// Параметры: +// ОписаниеСобытия - см. ЮТФабрикаСлужебный.ОписаниеСобытияИсполненияТестов +Процедура ПослеКаждогоТеста(ОписаниеСобытия) Экспорт + + Контекст = Контекст(); + Если НЕ ЛогированиеВключено(Контекст) Тогда + Возврат; + КонецЕсли; + + ЮТОбщий.Инкремент(Контекст.КоличествоВыполненныхТестов); + ЮТЛогирование.Информация(СтрШаблон("%1 Завершен тест `%2`", Прогресс(), ОписаниеСобытия.Тест.Имя)); + +КонецПроцедуры + +// Перед каждым тестом. +// +// Параметры: +// ОписаниеСобытия - см. ЮТФабрикаСлужебный.ОписаниеСобытияИсполненияТестов +Процедура ПослеТестовогоНабора(ОписаниеСобытия) Экспорт + + ЮТЛогирование.Информация(СтрШаблон("Завершен тестовый набор `%1`", ОписаниеСобытия.Набор.Имя)); + +КонецПроцедуры + +// Перед каждым тестом. +// +// Параметры: +// ОписаниеСобытия - см. ЮТФабрикаСлужебный.ОписаниеСобытияИсполненияТестов +Процедура ПослеВсехТестов(ОписаниеСобытия) Экспорт + + Контекст = Контекст(); + Если НЕ ЛогированиеВключено(Контекст) Тогда + Возврат; + КонецЕсли; +#Если Клиент Тогда + ЮТКонтекстСлужебный.УстановитьЗначениеКонтекста(ИмяКонтекстаЛогирования() + ".КоличествоВыполненныхТестов", Контекст.КоличествоВыполненныхТестов, Истина); +#КонецЕсли + + ЮТЛогирование.Информация(СтрШаблон("Завершен модуль `%1`", ОписаниеСобытия.Модуль.МетаданныеМодуля.ПолноеИмя)); + +КонецПроцедуры + +#КонецОбласти + +#КонецОбласти + +#Область СлужебныеПроцедурыИФункции + +#Область Запись + +Функция ЛогированиеВключено(Знач Контекст = Неопределено, Приоритет = Неопределено) + + Если Контекст = Неопределено Тогда + Контекст = Контекст(); + КонецЕсли; + + Возврат Контекст <> Неопределено И Контекст.Включено И (Приоритет = Неопределено ИЛИ Контекст.УровеньЛога <= Приоритет); + +КонецФункции + +Процедура ЗаписатьСообщения(Контекст, Сообщения, Дописывать = Истина) + +#Если ВебКлиент Тогда + ВызватьИсключение ЮТИсключения.МетодНеДоступен("ЗаписатьСообщения"); +#Иначе + Если Контекст.ВыводВКонсоль Тогда + ЗаписатьЛогВКонсоль(Сообщения); + КонецЕсли; + + Если ЗначениеЗаполнено(Контекст.ФайлЛога) Тогда + ЗаписатьЛогВФайл(Контекст.ФайлЛога, Сообщения, Дописывать); + КонецЕсли; +#КонецЕсли + +КонецПроцедуры + +Процедура ЗаписатьЛогВФайл(ФайлЛога, Сообщения, Дописывать = Истина) + +#Если ВебКлиент Тогда + ВызватьИсключение ЮТИсключения.МетодНеДоступен("ЗаписатьЛогВФайл"); +#Иначе + Запись = Новый ЗаписьТекста(ФайлЛога, КодировкаТекста.UTF8, , Дописывать); + + Для Каждого Сообщение Из Сообщения Цикл + Запись.ЗаписатьСтроку(Сообщение); + КонецЦикла; + + Запись.Закрыть(); +#КонецЕсли + +КонецПроцедуры + +Процедура ЗаписатьЛогВКонсоль(Сообщения) + +#Если ВебКлиент Тогда + ВызватьИсключение ЮТИсключения.МетодНеДоступен("ЗаписатьЛогВКонсоль"); +#Иначе + //@skip-check empty-except-statement + Попытка + Для Каждого Сообщение Из Сообщения Цикл + ЮТОбщий.ВывестиВКонсоль(Сообщение); + КонецЦикла; + Исключение + // Игнорируем ошибку + КонецПопытки; +#КонецЕсли + +КонецПроцедуры + +Функция Прогресс() + + Контекст = Контекст(); + Прогресс = Окр(100 * Контекст.КоличествоВыполненныхТестов / Контекст.ОбщееКоличествоТестов, 0); + + Возврат СтрШаблон("%1%% (%2/%3)", Прогресс, Контекст.КоличествоВыполненныхТестов, Контекст.ОбщееКоличествоТестов); + +КонецФункции + +#КонецОбласти + +#Область Контекст + +// Контекст. +// +// Возвращаемое значение: +// см. НовыйДанныеКонтекста +Функция Контекст() + + Возврат ЮТКонтекстСлужебный.ЗначениеКонтекста(ИмяКонтекстаЛогирования()); + +КонецФункции + +Функция ИмяКонтекстаЛогирования() + + Возврат "КонтекстЛогирования"; + +КонецФункции + +// Новый данные контекста. +// +// Возвращаемое значение: +// Структура - Новый данные контекста: +// * Включено - Булево - Логирование включено +// * ФайлЛога - Неопределено - Файл вывода лога +// * ВыводВКонсоль- Булево - Вывод лога в консоль +// * ФайлЛогаДоступенНаСервере - Булево - Файл лога доступен на сервере +// * НакопленныеЗаписи - Массив из Строка - Буфер для серверных сообщений +// * ОбщееКоличествоТестов - Число +// * КоличествоВыполненныхТестов - Число +// * УровеньЛога - Число - Уровень логирования +Функция НовыйДанныеКонтекста() + + ДанныеКонтекста = Новый Структура(); + ДанныеКонтекста.Вставить("Включено", Ложь); + ДанныеКонтекста.Вставить("ФайлЛога", Неопределено); + ДанныеКонтекста.Вставить("ВыводВКонсоль", Ложь); + ДанныеКонтекста.Вставить("ФайлЛогаДоступенНаСервере", Ложь); + ДанныеКонтекста.Вставить("НакопленныеЗаписи", Новый Массив()); + ДанныеКонтекста.Вставить("ОбщееКоличествоТестов", 0); + ДанныеКонтекста.Вставить("КоличествоВыполненныхТестов", 0); + ДанныеКонтекста.Вставить("УровеньЛога", 0); + + Возврат ДанныеКонтекста; + +КонецФункции + +#КонецОбласти + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТЛогированиеСлужебныйВызовСервера.xml b/src/cfe/YAXUnit/CommonModules/ЮТЛогированиеСлужебныйВызовСервера.xml new file mode 100644 index 0000000..a4fd111 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТЛогированиеСлужебныйВызовСервера.xml @@ -0,0 +1,23 @@ + + + + + ЮТЛогированиеСлужебныйВызовСервера + + + ru + Логирование (вызов сервера) + + + + false + false + true + false + false + true + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТЛогированиеСлужебныйВызовСервера/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТЛогированиеСлужебныйВызовСервера/Ext/Module.bsl new file mode 100644 index 0000000..680d529 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТЛогированиеСлужебныйВызовСервера/Ext/Module.bsl @@ -0,0 +1,45 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область СлужебныйПрограммныйИнтерфейс + +Функция НакопленныеСообщенияЛогирования(Знач Очистить = Ложь) Экспорт + + Возврат ЮТЛогированиеСлужебный.НакопленныеСообщенияЛогирования(Очистить); + +КонецФункции + +Функция ФайлЛогаДоступенНаСервере(Знач ИмяФайла, Знач ЗначениеПроверки) Экспорт + + Попытка + + Чтение = Новый ЧтениеТекста(ИмяФайла); + Строка = Чтение.ПрочитатьСтроку(); + Чтение.Закрыть(); + + Возврат Строка = ЗначениеПроверки; + + Исключение + + Возврат Ложь; + + КонецПопытки; + +КонецФункции + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТЛокальСлужебный.xml b/src/cfe/YAXUnit/CommonModules/ЮТЛокальСлужебный.xml new file mode 100644 index 0000000..c769b3c --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТЛокальСлужебный.xml @@ -0,0 +1,23 @@ + + + + + ЮТЛокальСлужебный + + + ru + Локаль служебный + + + + false + true + true + false + true + false + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТЛокальСлужебный/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТЛокальСлужебный/Ext/Module.bsl new file mode 100644 index 0000000..9cedb36 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТЛокальСлужебный/Ext/Module.bsl @@ -0,0 +1,50 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2023 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область СлужебныйПрограммныйИнтерфейс + +Функция ЛокальПлатформы() Экспорт + + Возврат ТекущийЯзыкСистемы(); + +КонецФункции + +Функция ЭтоАнглийскаяЛокальПлатформы() Экспорт + + Возврат ЛокальПлатформы() = "en"; + +КонецФункции + +Функция ЭтоРусскаяЛокальПлатформы() Экспорт + + Возврат ЛокальПлатформы() = "ru"; + +КонецФункции + +Функция ЛокальИнтерфейса() Экспорт + +#Если Клиент Тогда + Возврат ТекущийЯзык(); +#Иначе + Возврат ТекущийЯзык().КодЯзыка; +#КонецЕсли + +КонецФункции + +#КонецОбласти + diff --git a/src/cfe/YAXUnit/CommonModules/ЮТМетаданные.xml b/src/cfe/YAXUnit/CommonModules/ЮТМетаданные.xml new file mode 100644 index 0000000..bbc2fc2 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТМетаданные.xml @@ -0,0 +1,23 @@ + + + + + ЮТМетаданные + + + ru + Метаданные + + + + false + true + true + false + true + false + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТМетаданные/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТМетаданные/Ext/Module.bsl new file mode 100644 index 0000000..9c543f2 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТМетаданные/Ext/Module.bsl @@ -0,0 +1,256 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область ПрограммныйИнтерфейс + +// Модули подсистемы. +// Возвращает список модулей подсистемы +// Подсистема должна находится в подсистеме "ЮТДинамическиПодключаемые" +// Параметры: +// ИмяПодсистемы - Строка - Имя подсистемы +// Серверные - Булево - Возвращять модули доступные на сервере +// Клиентские - Булево - Возвращять модули доступные на клиенте +// Возвращаемое значение: +// Массив из Строка - Имена модулей входящих в подсистему +Функция МодулиПодсистемы(ИмяПодсистемы, Серверные = Истина, Клиентские = Истина) Экспорт + + Возврат ЮТМетаданныеСлужебныйПовтИсп.МодулиПодсистемы(ИмяПодсистемы, Серверные, Клиентские); + +КонецФункции + +// Описание объекта метаданных. +// +// Параметры: +// Значение - ОбъектМетаданных +// - Тип - Тип объекта информационной базы +// - Строка - Полное имя объекта метаданных +// - см. СтруктураОписанияОбъектаМетаданных +// - Произвольный - Объект информационной базы +// +// Возвращаемое значение: +// см. СтруктураОписанияОбъектаМетаданных +Функция ОписаниеОбъектаМетаданных(Знач Значение) Экспорт + + Если ЮТМетаданныеСлужебный.ЭтоОписаниеОбъектаМетаданных(Значение) Тогда + //@skip-check constructor-function-return-section + Возврат Значение; + КонецЕсли; + + ТипЗначения = ТипЗнч(Значение); + + ТипТип = Тип("Тип"); +#Если Сервер Тогда + Если ТипЗначения = Тип("ОбъектМетаданных") Тогда + Значение = Значение.ПолноеИмя(); + ТипЗначения = Тип("Строка"); + КонецЕсли; +#КонецЕсли + + Если ТипЗначения <> ТипТип И ТипЗначения <> Тип("Строка") Тогда + Значение = ТипЗнч(Значение); + ТипЗначения = ТипТип; + КонецЕсли; + + Если ТипЗначения = ТипТип Тогда + ИдентификаторТипа = ЮТТипыДанныхСлужебный.ИдентификаторТипа(Значение); // Для работы кэширования + //@skip-check constructor-function-return-section + Возврат ЮТМетаданныеСлужебныйПовтИсп.ОписаниеОбъектаМетаданныхПоИдентификаторуТипа(ИдентификаторТипа); + Иначе + //@skip-check constructor-function-return-section + Возврат ЮТМетаданныеСлужебныйПовтИсп.ОписаниеОбъектаМетаданных(Значение); + КонецЕсли; + +КонецФункции + +// Возвращает нормализованное имя таблицы, то которое можно использовать в запросах +// +// Параметры: +// Значение - ОбъектМетаданных +// - Тип - Тип объекта информационной базы +// - Строка - Полное имя объекта метаданных +// - см. СтруктураОписанияОбъектаМетаданных +// - Произвольный - Объект информационной базы +// +// Возвращаемое значение: +// Строка - Нормализованное имя таблицы +Функция НормализованноеИмяТаблицы(Значение) Экспорт + + Описание = ОписаниеОбъектаМетаданных(Значение); + + Возврат СтрШаблон("%1.%2", Описание.ОписаниеТипа.Имя, Описание.Имя); + +КонецФункции + +// Проверка, что переданное значение относится к перечислениям. +// +// Параметры: +// Значение - ОбъектМетаданных +// - Тип - Тип объекта информационной базы +// - Строка - Полное имя объекта метаданных +// - см. СтруктураОписанияОбъектаМетаданных +// - Произвольный - Объект информационной базы +// +// Возвращаемое значение: +// Булево - Это перечисление +Функция ЭтоПеречисление(Значение) Экспорт + + Описание = ОписаниеОбъектаМетаданных(Значение); + Возврат Описание <> Неопределено И Описание.ОписаниеТипа.Имя = "Перечисление"; + +КонецФункции + +// Проверка, что переданное значение относится к регистрам. +// +// Параметры: +// Значение - ОбъектМетаданных +// - Тип - Тип объекта информационной базы +// - Строка - Полное имя объекта метаданных +// - см. СтруктураОписанияОбъектаМетаданных +// - Произвольный - Объект информационной базы +// +// Возвращаемое значение: +// Булево - Это перечисление +Функция ЭтоРегистр(Значение) Экспорт + + Описание = ОписаниеОбъектаМетаданных(Значение); + Возврат Описание <> Неопределено И СтрНачинаетсяС(Описание.ОписаниеТипа.Имя, "Регистр"); + +КонецФункции + +// Разрешены ли синхронные вызовы в параметрах конфигурации. +// +// Возвращаемое значение: +// Булево - Разрешены синхронные вызовы +Функция РазрешеныСинхронныеВызовы() Экспорт + + Возврат ЮТМетаданныеСлужебныйПовтИсп.РазрешеныСинхронныеВызовы(); + +КонецФункции + +// Возвращяет набор регистров движений документа +// +// Параметры: +// Документ - ОбъектМетаданных +// - Тип - Тип объекта информационной базы +// - Строка - Полное имя объекта метаданных +// - см. СтруктураОписанияОбъектаМетаданных +// - ДокументСсылка, ДокументОбъект - Объект информационной базы +// - ДокументМенеджер - Менеджер вида документа +// +// Возвращаемое значение: +// Структура - Регистры движений документа. Ключи - Имя регистра, Значение - Полное имя регистра +Функция РегистрыДвиженийДокумента(Документ) Экспорт + + ОписаниеОбъектаМетаданных = ОписаниеОбъектаМетаданных(Документ); + + ПолноеИмя = СтрШаблон("%1.%2", ОписаниеОбъектаМетаданных.ОписаниеТипа.ИмяКоллекции, ОписаниеОбъектаМетаданных.Имя); + + Возврат ЮТМетаданныеСлужебныйПовтИсп.РегистрыДвиженийДокумента(ПолноеИмя); + +КонецФункции + +// Возвращает текущую версию тестового движка (YAxUnit) +// +// Возвращаемое значение: +// Строка - Версия движка +Функция ВерсияДвижка() Экспорт + + Возврат ЮТМетаданныеСлужебныйПовтИсп.ВерсияДвижка(); + +КонецФункции + +// Описание типа объекта метаданных. +// +// Возвращаемое значение: +// Структура - Описание типа метаданных: +// * Имя - Строка +// * ИмяКоллекции - Строка +// * Конструктор - Строка +// * Группы - Булево +// * Ссылочный - Булево +// * Регистр - Булево +// * ОбработкаОтчет - Булево +// * СтандартныеРеквизиты - Булево +// * Реквизиты - Булево +// * Измерения - Булево +// * Ресурсы - Булево +// * РеквизитыАдресации - Булево +// * ТабличныеЧасти - Булево +Функция ОписаниеТипаМетаданных() Экспорт + + Описание = Новый Структура(); + Описание.Вставить("Имя", ""); + Описание.Вставить("ИмяКоллекции", ""); + Описание.Вставить("Конструктор", ""); + Описание.Вставить("Группы", Ложь); + Описание.Вставить("Ссылочный", Ложь); + Описание.Вставить("Регистр", Ложь); + Описание.Вставить("ОбработкаОтчет", Ложь); + Описание.Вставить("СтандартныеРеквизиты", Ложь); + Описание.Вставить("Реквизиты", Ложь); + Описание.Вставить("Измерения", Ложь); + Описание.Вставить("Ресурсы", Ложь); + Описание.Вставить("РеквизитыАдресации", Ложь); + Описание.Вставить("ТабличныеЧасти", Ложь); + + Возврат Описание; + +КонецФункции + +// Описание объекта метаданных. +// +// Возвращаемое значение: +// Структура - Описание объекта метаданных: +// * Имя - Строка +// * ОписаниеТипа - см. ОписаниеТипаМетаданных +// * Реквизиты - Структура +// * ТабличныеЧасти - Структура +Функция СтруктураОписанияОбъектаМетаданных() Экспорт + + Описание = Новый Структура; + Описание.Вставить("Имя", ""); + Описание.Вставить("ОписаниеТипа", Неопределено); + Описание.Вставить("Реквизиты", Новый Структура()); + Описание.Вставить("ТабличныеЧасти", Новый Структура()); + + //@skip-check constructor-function-return-section + Возврат Описание; + +КонецФункции + +// Описание реквизита объекта метаданных +// +// Возвращаемое значение: +// Структура - Описание реквизита: +// * Имя - Строка +// * Тип - ОписаниеТипов +// * Обязательный - Булево +// * ЭтоКлюч - Булево +Функция ОписаниеРеквизита() Экспорт + + Описание = Новый Структура(); + Описание.Вставить("Имя", ""); + Описание.Вставить("Тип", Новый ОписаниеТипов("Неопределено")); + Описание.Вставить("Обязательный", Ложь); + Описание.Вставить("ЭтоКлюч", Ложь); + + Возврат Описание; + +КонецФункции + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТМетаданныеСлужебный.xml b/src/cfe/YAXUnit/CommonModules/ЮТМетаданныеСлужебный.xml new file mode 100644 index 0000000..72f316d --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТМетаданныеСлужебный.xml @@ -0,0 +1,23 @@ + + + + + ЮТМетаданныеСлужебный + + + ru + Метаданные служебный + + + + false + true + true + false + true + false + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТМетаданныеСлужебный/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТМетаданныеСлужебный/Ext/Module.bsl new file mode 100644 index 0000000..e6d9c28 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТМетаданныеСлужебный/Ext/Module.bsl @@ -0,0 +1,31 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область СлужебныйПрограммныйИнтерфейс + +Функция ЭтоОписаниеОбъектаМетаданных(Значение) Экспорт + + Возврат ЮТТипыДанныхСлужебный.ЭтоСтруктура(ТипЗнч(Значение)) И ЮТОбщий.ЭтаСтруктураИмеетТип(Значение, "ОписаниеОбъектаМетаданных"); + +КонецФункции + +#КонецОбласти + +#Область СлужебныеПроцедурыИФункции + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТМетаданныеСлужебныйВызовСервера.xml b/src/cfe/YAXUnit/CommonModules/ЮТМетаданныеСлужебныйВызовСервера.xml new file mode 100644 index 0000000..8fd7b3f --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТМетаданныеСлужебныйВызовСервера.xml @@ -0,0 +1,23 @@ + + + + + ЮТМетаданныеСлужебныйВызовСервера + + + ru + Метаданные (сервер) + + + + false + false + true + false + true + true + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТМетаданныеСлужебныйВызовСервера/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТМетаданныеСлужебныйВызовСервера/Ext/Module.bsl new file mode 100644 index 0000000..357f2d7 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТМетаданныеСлужебныйВызовСервера/Ext/Module.bsl @@ -0,0 +1,379 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область СлужебныйПрограммныйИнтерфейс + +// МодулиРасширений +// Выполняет чтение метаданных общих модулей, которые предположительно могут являться тестами +// +// Возвращаемое значение: +// Массив из см. ЮТФабрикаСлужебный.ОписаниеМодуля - Коллекция описаний моделей, структуру элемента см. ЮТФабрикаСлужебный.ОписаниеМодуля +Функция МодулиРасширений() Экспорт + + УстановитьПривилегированныйРежим(Истина); + + МетаданныеМодулей = Новый Массив; + + Для Каждого Модуль Из Метаданные.ОбщиеМодули Цикл + + Если Модуль.РасширениеКонфигурации() <> Неопределено Тогда + + МетаданныеМодуля = МетаданныеМодуля(Модуль); + МетаданныеМодулей.Добавить(МетаданныеМодуля); + + КонецЕсли; + + КонецЦикла; + + Возврат МетаданныеМодулей; + +КонецФункции + +// Модули подсистемы. +// Возвращает список модулей подсистемы +// Подсистема должна находится в подсистеме "ЮТДинамическиПодключаемые" +// Параметры: +// ИмяПодсистемы - Строка - Имя подсистемы +// Серверные - Булево - Возвращять модули доступные на сервере +// Клиентские - Булево - Возвращять модули доступные на клиенте +// +// Возвращаемое значение: +// Массив из Строка - Имена модулей входящих в подсистему +Функция МодулиПодсистемы(Знач ИмяПодсистемы, Знач Серверные, Знач Клиентские) Экспорт + + Подсистема = Метаданные.Подсистемы.ЮТДинамическиПодключаемые.Подсистемы.Найти(ИмяПодсистемы); + + Если Подсистема = Неопределено Тогда + + ВызватьИсключение СтрШаблон("Подсистема ""%1"" не найдена", ИмяПодсистемы); + + КонецЕсли; + + Модули = Новый Массив(); + + Для Каждого Объект Из Подсистема.Состав Цикл + + Если Метаданные.ОбщиеМодули.Содержит(Объект) Тогда + + Добавить = (Серверные И Клиентские) + ИЛИ (Серверные И (Объект.Сервер)) + ИЛИ (Клиентские И (Объект.КлиентУправляемоеПриложение Или Объект.ВызовСервера)); + // КлиентОбычноеПриложение сознательно не анализируется, он должен идти в паре с другой настройкой + + Если Добавить Тогда + Модули.Добавить(Объект.Имя); + КонецЕсли; + + КонецЕсли; + + КонецЦикла; + + Возврат Модули; + +КонецФункции + +Функция МетаданныеМодуля(Знач Модуль) Экспорт + + Если ТипЗнч(Модуль) = Тип("Строка") Тогда + ИмяМодуля = Модуль; + Модуль = Метаданные.ОбщиеМодули.Найти(ИмяМодуля); + + Если Модуль = Неопределено Тогда + ВызватьИсключение "Не найден модуль с именем " + ИмяМодуля; + КонецЕсли; + КонецЕсли; + + Описание = ЮТФабрикаСлужебный.ОписаниеМодуля(); + Описание.Имя = Модуль.Имя; + Описание.КлиентУправляемоеПриложение = Модуль.КлиентУправляемоеПриложение; + Описание.КлиентОбычноеПриложение = Модуль.КлиентОбычноеПриложение; + Описание.Глобальный = Модуль.Глобальный; + Описание.Сервер = Модуль.Сервер; + Описание.ВызовСервера = Модуль.ВызовСервера; + Описание.Расширение = Модуль.РасширениеКонфигурации().Имя; + Описание.ПолноеИмя = СтрШаблон("%1.%2", Описание.Расширение, Модуль.Имя); + + Возврат Описание; + +КонецФункции + +Функция ОписаниеОбъектаМетаданных(Знач Значение, ЗаполнятьРеквизиты = Истина) Экспорт + + МетаданныеОбъекта = ОбъектМетаданных(Значение); + ОписаниеТипа = ОписаниеТипаМетаданных(МетаданныеОбъекта); + + ОписаниеОбъект = ЮТМетаданные.СтруктураОписанияОбъектаМетаданных(); + ОписаниеОбъект.Имя = МетаданныеОбъекта.Имя; + ОписаниеОбъект.ОписаниеТипа = ОписаниеТипа; + ЮТОбщий.УказатьТипСтруктуры(ОписаниеОбъект, "ОписаниеОбъектаМетаданных"); + + Если НЕ ЗаполнятьРеквизиты Тогда + Возврат ОписаниеОбъект; + КонецЕсли; + + Если ОписаниеТипа.СтандартныеРеквизиты Тогда + ДобавитьОписанияРеквизитов(МетаданныеОбъекта.СтандартныеРеквизиты, ОписаниеОбъект.Реквизиты, "Ссылка, Период"); + КонецЕсли; + + Если ОписаниеТипа.Измерения Тогда + ДобавитьОписанияРеквизитов(МетаданныеОбъекта.Измерения, ОписаниеОбъект.Реквизиты, Истина); + КонецЕсли; + + Если ОписаниеТипа.Реквизиты Тогда + ДобавитьОписанияРеквизитов(МетаданныеОбъекта.Реквизиты, ОписаниеОбъект.Реквизиты, Ложь); + КонецЕсли; + + Если ОписаниеТипа.Ресурсы Тогда + ДобавитьОписанияРеквизитов(МетаданныеОбъекта.Ресурсы, ОписаниеОбъект.Реквизиты, Ложь); + КонецЕсли; + + Если ОписаниеТипа.РеквизитыАдресации Тогда + ДобавитьОписанияРеквизитов(МетаданныеОбъекта.РеквизитыАдресации, ОписаниеОбъект.Реквизиты, Ложь); + КонецЕсли; + + ДобавитьОбщиеРеквизиты(МетаданныеОбъекта, ОписаниеОбъект.Реквизиты); + + Если ОписаниеТипа.ТабличныеЧасти Тогда + + Для Каждого ТабличнаяЧасть Из МетаданныеОбъекта.ТабличныеЧасти Цикл + РеквизитыТабличнойЧасти = Новый Структура(); + ДобавитьОписанияРеквизитов(ТабличнаяЧасть.Реквизиты, РеквизитыТабличнойЧасти, Ложь); + + ОписаниеОбъект.ТабличныеЧасти.Вставить(ТабличнаяЧасть.Имя, РеквизитыТабличнойЧасти); + КонецЦикла; + + КонецЕсли; + + Возврат Новый ФиксированнаяСтруктура(ОписаниеОбъект); + +КонецФункции + +// Описание типа метаданных. +// +// Параметры: +// МетаданныеОбъекта - Тип, ОбъектМетаданных - Тип +// +// Возвращаемое значение: +// см. ЮТМетаданные.ОписаниеТипаМетаданных +Функция ОписаниеТипаМетаданных(Знач МетаданныеОбъекта) Экспорт + + Если ТипЗнч(МетаданныеОбъекта) = Тип("Тип") Тогда + МетаданныеОбъекта = Метаданные.НайтиПоТипу(МетаданныеОбъекта); + КонецЕсли; + + ПолноеИмя = МетаданныеОбъекта.ПолноеИмя(); + ЧастиИмени = СтрРазделить(ПолноеИмя, "."); + Типы = ЮТМетаданныеСлужебныйПовтИсп.ТипыМетаданных(); + + Если НЕ Типы.Свойство(ЧастиИмени[0]) Тогда + Сообщение = СтрШаблон("Получение описания для '%1' не поддерживается, либо не реализовано", ЧастиИмени[0]); + ВызватьИсключение Сообщение; + КонецЕсли; + + Описание = ЮТМетаданные.ОписаниеТипаМетаданных(); + ЗаполнитьЗначенияСвойств(Описание, Типы[ЧастиИмени[0]]); + //@skip-check constructor-function-return-section + Возврат Новый ФиксированнаяСтруктура(Описание); + +КонецФункции + +Функция ТипыМетаданных() Экспорт + + Макет = ПолучитьОбщийМакет("ЮТОписаниеМетаданных").ПолучитьТекст(); + КоллекцияОписаний = ЮТТестовыеДанные.ТаблицаMarkDown(Макет); + + ТипыМетаданных = Новый Структура(); + + Для Каждого Запись Из КоллекцияОписаний Цикл + + Описание = Новый Структура(); + Описание.Вставить("Имя", Запись.Имя); + Описание.Вставить("ИмяКоллекции", Запись.ИмяКоллекции); + Описание.Вставить("Конструктор", Запись.Конструктор); + Описание.Вставить("Группы", Запись.Группы = "+"); + Описание.Вставить("Ссылочный", Запись.Ссылочный = "+"); + Описание.Вставить("Реквизиты", Запись.Реквизиты = "+"); + Описание.Вставить("Измерения", Запись.Измерения = "+"); + Описание.Вставить("Ресурсы", Запись.Ресурсы = "+"); + Описание.Вставить("РеквизитыАдресации", Запись.РеквизитыАдресации = "+"); + Описание.Вставить("ТабличныеЧасти", Запись.ТабличныеЧасти = "+"); + Описание.Вставить("СтандартныеРеквизиты", Запись.СтандартныеРеквизиты = "+"); + Описание.Вставить("ОбработкаОтчет", Запись.Имя = "Обработка" ИЛИ Запись.Имя = "Отчет"); + Описание.Вставить("Регистр", СтрНачинаетсяС(Запись.Имя, "Регистр")); + + ТипыМетаданных.Вставить(Описание.Имя, Описание); + ТипыМетаданных.Вставить(Описание.ИмяКоллекции, Описание); + + КонецЦикла; + + Возврат ТипыМетаданных; + +КонецФункции + +Функция РазрешеныСинхронныеВызовы() Экспорт + + Возврат Метаданные.РежимИспользованияСинхронныхВызововРасширенийПлатформыИВнешнихКомпонент + = Метаданные.СвойстваОбъектов.РежимИспользованияСинхронныхВызововРасширенийПлатформыИВнешнихКомпонент.Использовать; + +КонецФункции + +Функция РегистрыДвиженийДокумента(ПолноеИмя) Экспорт + + ОбъектМетаданных = ОбъектМетаданных(ПолноеИмя); + + Если НЕ Метаданные.Документы.Содержит(ОбъектМетаданных) Тогда + ВызватьИсключение "Движения доступны только для документов. Не поддерживается получение движений для " + ПолноеИмя; + КонецЕсли; + + Регистры = Новый Структура; + + Для Каждого Регистр Из ОбъектМетаданных.Движения Цикл + + Регистры.Вставить(Регистр.Имя, Регистр.ПолноеИмя()); + + КонецЦикла; + + Возврат Регистры; + +КонецФункции + +Функция ВариантВстроенногоЯзыка() Экспорт + + Возврат String(Metadata.ScriptVariant); + +КонецФункции + +#КонецОбласти + +#Область СлужебныеПроцедурыИФункции + +Функция ОбъектМетаданных(Значение) + + ТипЗначение = ТипЗнч(Значение); + + Если ТипЗначение = Тип("Тип") Тогда + + ОбъектМетаданных = Метаданные.НайтиПоТипу(Значение); + + ИначеЕсли ТипЗначение = Тип("ОбъектМетаданных") Тогда + + ОбъектМетаданных = Значение; + + ИначеЕсли ТипЗначение = Тип("Строка") Тогда + + ОбъектМетаданных = ОбъектМетаданныхИзСтроки(Значение); + + ИначеЕсли ЮТТипыДанныхСлужебный.ЭтоСтруктура(ТипЗначение) И Значение.Свойство("ОписаниеТипа") И Значение.Свойство("Имя") Тогда + + ОбъектМетаданных = Метаданные[Значение.ОписаниеТипа.ИмяКоллекции][Значение.Имя]; + + Иначе + + ОбъектМетаданных = Неопределено; + + КонецЕсли; + + Если ОбъектМетаданных = Неопределено Тогда + Сообщение = ЮТИсключения.НеподдерживаемыйПараметрМетода("ЮТМетаданныеСлужебныйВызовСервера.ОбъектМетаданных", Значение); + ВызватьИсключение Сообщение; + КонецЕсли; + + Возврат ОбъектМетаданных; + +КонецФункции + +Функция ОбъектМетаданныхИзСтроки(Значение) + + ЧастиСтроки = СтрРазделить(Значение, "."); + + Если ЧастиСтроки.Количество() = 2 Тогда + + ТипыМетаданных = ЮТМетаданныеСлужебныйПовтИсп.ТипыМетаданных(); + ОписаниеТипа = ТипыМетаданных[ЧастиСтроки[0]]; + Если ОписаниеТипа <> Неопределено Тогда + ОбъектМетаданных = Метаданные[ОписаниеТипа.ИмяКоллекции].Найти(ЧастиСтроки[1]); + + Если ОбъектМетаданных = Неопределено Тогда + ВызватьИсключение "Не найден объект метаданных " + Значение; + КонецЕсли; + + КонецЕсли; + + КонецЕсли; + + Возврат ОбъектМетаданных; + +КонецФункции + +Процедура ДобавитьОписанияРеквизитов(КоллекцияРеквизитов, КоллекцияОписаний, Знач ЭтоКлюч) + + Если ТипЗнч(ЭтоКлюч) = Тип("Строка") Тогда + ИменаКлючевыхПолей = СтрРазделить(ЭтоКлюч, ", "); + КонецЕсли; + + Для Каждого Реквизит Из КоллекцияРеквизитов Цикл + + Если ИменаКлючевыхПолей <> Неопределено Тогда + ЭтоКлюч = ИменаКлючевыхПолей.Найти(Реквизит.Имя) <> Неопределено; + КонецЕсли; + + КоллекцияОписаний.Вставить(Реквизит.Имя, НовоеОписаниеРеквизита(Реквизит, ЭтоКлюч)); + + КонецЦикла; + +КонецПроцедуры + +Процедура ДобавитьОбщиеРеквизиты(МетаданныеОбъекта, КоллекцияОписаний) + + Использовать = Метаданные.СвойстваОбъектов.ИспользованиеОбщегоРеквизита.Использовать; + Авто = Метаданные.СвойстваОбъектов.ИспользованиеОбщегоРеквизита.Авто; + АвтоИспользование = Метаданные.СвойстваОбъектов.АвтоИспользованиеОбщегоРеквизита.Использовать; + + Для Каждого Реквизит Из Метаданные.ОбщиеРеквизиты Цикл + + ЭлементСостава = Реквизит.Состав.Найти(МетаданныеОбъекта); + + Если ЭлементСостава = Неопределено Тогда + Продолжить; + ИначеЕсли ЭлементСостава.Использование = Использовать Или Реквизит.АвтоИспользование = АвтоИспользование И ЭлементСостава.Использование = Авто Тогда + КоллекцияОписаний.Вставить(Реквизит.Имя, НовоеОписаниеРеквизита(Реквизит, Ложь)); + КонецЕсли; + + КонецЦикла; + +КонецПроцедуры + +Функция НовоеОписаниеРеквизита(Реквизит, ЭтоКлюч) + + Описание = ЮТМетаданные.ОписаниеРеквизита(); + Описание.Имя = Реквизит.Имя; + Описание.Тип = Реквизит.Тип; + Описание.Обязательный = Реквизит.ПроверкаЗаполнения = ПроверкаЗаполнения.ВыдаватьОшибку; + Описание.ЭтоКлюч = ЭтоКлюч; + + Возврат Описание; + +КонецФункции + +Функция ВерсияДвижка() Экспорт + + Возврат Метаданные.ОбщиеМодули.ЮТМетаданныеСлужебныйВызовСервера.РасширениеКонфигурации().Версия; + +КонецФункции + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТМетаданныеСлужебныйПовтИсп.xml b/src/cfe/YAXUnit/CommonModules/ЮТМетаданныеСлужебныйПовтИсп.xml new file mode 100644 index 0000000..2cadde2 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТМетаданныеСлужебныйПовтИсп.xml @@ -0,0 +1,23 @@ + + + + + ЮТМетаданныеСлужебныйПовтИсп + + + ru + Метаданные (повторного использования) + + + + false + true + true + false + true + false + false + DuringSession + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТМетаданныеСлужебныйПовтИсп/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТМетаданныеСлужебныйПовтИсп/Ext/Module.bsl new file mode 100644 index 0000000..8d826e7 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТМетаданныеСлужебныйПовтИсп/Ext/Module.bsl @@ -0,0 +1,70 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область СлужебныйПрограммныйИнтерфейс + +Функция МодулиПодсистемы(ИмяПодсистемы, Серверные, Клиентские) Экспорт + + Возврат ЮТМетаданныеСлужебныйВызовСервера.МодулиПодсистемы(ИмяПодсистемы, Серверные, Клиентские); + +КонецФункции + +Функция ОписаниеОбъектаМетаданных(Знач Менеджер) Экспорт + + Возврат ЮТМетаданныеСлужебныйВызовСервера.ОписаниеОбъектаМетаданных(Менеджер); + +КонецФункции + +Функция ОписаниеОбъектаМетаданныхПоИдентификаторуТипа(Знач ИдентификаторТипа) Экспорт + + Тип = ЮТТипыДанныхСлужебный.ТипПоИдентификатору(ИдентификаторТипа); + Возврат ЮТМетаданныеСлужебныйВызовСервера.ОписаниеОбъектаМетаданных(Тип); + +КонецФункции + +Функция ТипыМетаданных() Экспорт + + Возврат ЮТМетаданныеСлужебныйВызовСервера.ТипыМетаданных(); + +КонецФункции + +Функция РазрешеныСинхронныеВызовы() Экспорт + + Возврат ЮТМетаданныеСлужебныйВызовСервера.РазрешеныСинхронныеВызовы(); + +КонецФункции + +Функция РегистрыДвиженийДокумента(ПолноеИмя) Экспорт + + Возврат ЮТМетаданныеСлужебныйВызовСервера.РегистрыДвиженийДокумента(ПолноеИмя); + +КонецФункции + +Функция ВариантВстроенногоЯзыка() Экспорт + + Возврат ЮТМетаданныеСлужебныйВызовСервера.ВариантВстроенногоЯзыка(); + +КонецФункции + +Функция ВерсияДвижка() Экспорт + + Возврат ЮТМетаданныеСлужебныйВызовСервера.ВерсияДвижка(); + +КонецФункции + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТМетодыСлужебный.xml b/src/cfe/YAXUnit/CommonModules/ЮТМетодыСлужебный.xml new file mode 100644 index 0000000..10b573e --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТМетодыСлужебный.xml @@ -0,0 +1,23 @@ + + + + + ЮТМетодыСлужебный + + + ru + Общий служебный + + + + false + true + true + false + true + false + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТМетодыСлужебный/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТМетодыСлужебный/Ext/Module.bsl new file mode 100644 index 0000000..1793479 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТМетодыСлужебный/Ext/Module.bsl @@ -0,0 +1,185 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область СлужебныйПрограммныйИнтерфейс + +Процедура ВызовУстаревшегоМетода(УстаревшийМетод, РекомендуемыйМетод, Версия) Экспорт + + Сообщение = СтрШаблон("Используется устаревший метод '%1'. В следующих релизах он будет удален", УстаревшийМетод); + + Если ЗначениеЗаполнено(РекомендуемыйМетод) Тогда + Сообщение = СтрШаблон("%1. Рекомендуется использовать '%2'", Сообщение, РекомендуемыйМетод); + КонецЕсли; + + ЮТЛогирование.Предостережение(Сообщение); + + Если ЮТСтроки.СравнитьВерсии(Версия, ВерсияЗапретаИспользованияУстаревших()) <= 0 Тогда + ВызватьИсключение Сообщение; + Иначе + ЮТОбщий.СообщитьПользователю(Сообщение); + КонецЕсли; + +КонецПроцедуры + +#Область ПроверкаМетодов + +// МетодМодуляСуществует +// Проверяет существование публичного (экспортного) метода у модуля +// +// Параметры: +// ИмяМодуля - Строка - Имя модуля, метод которого нужно поискать +// ИмяМетода - Строка - Имя метода, который ищем +// Кешировать - Булево - Признак кеширования результата проверки +// +// Возвращаемое значение: +// Булево - Метод найден +Функция МетодМодуляСуществует(ИмяМодуля, ИмяМетода, Кешировать = Истина) Экспорт + + ЮТПроверкиСлужебный.ПроверитьТипПараметра(ИмяМодуля, Тип("Строка"), "ЮТОбщий.МетодМодуляСуществует", "ИмяМодуля"); + ЮТПроверкиСлужебный.ПроверитьТипПараметра(ИмяМетода, Тип("Строка"), "ЮТОбщий.МетодМодуляСуществует", "ИмяМетода"); + + Если Кешировать Тогда + Возврат ЮТСлужебныйПовторногоИспользования.МетодМодуляСуществует(ИмяМодуля, ИмяМетода); + КонецЕсли; + + ПолноеИмяМетода = СтрШаблон("%1.%2", ИмяМодуля, ИмяМетода); + Алгоритм = ПолноеИмяМетода + "(,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,)"; + + Ошибка = ВыполнитьМетод(Алгоритм); + + ТипОшибки = ЮТРегистрацияОшибокСлужебный.ТипОшибки(Ошибка, ПолноеИмяМетода); + Возврат ТипОшибки = ЮТФабрикаСлужебный.ТипыОшибок().МногоПараметров; + +КонецФункции + +// Проверяет существование публичного (экспортного) метода у объекта +// +// Параметры: +// Объект - Произвольный - Объект, метод которого нужно поискать +// ИмяМетода - Строка - Имя метода, который ищем +// +// Возвращаемое значение: +// Булево - Метод найден +Функция МетодОбъектаСуществует(Объект, ИмяМетода) Экспорт + +#Если ВебКлиент Тогда + ВызватьИсключение ЮТИсключения.МетодНеДоступен("ЮТОбщий.МетодОбъектаСуществует"); +#Иначе + ЮТПроверкиСлужебный.ПроверитьТипПараметра(ИмяМетода, Тип("Строка"), "ЮТОбщий.МетодМодуляСуществует", "ИмяМетода"); + + ПолноеИмяМетода = СтрШаблон("Объект.%1", ИмяМетода); + Алгоритм = ПолноеИмяМетода + "(,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,)"; + + Ошибка = ВыполнитьМетод(Алгоритм, , Объект); + + ТипОшибки = ЮТРегистрацияОшибокСлужебный.ТипОшибки(Ошибка, ПолноеИмяМетода); + Возврат ТипОшибки = ЮТФабрикаСлужебный.ТипыОшибок().МногоПараметров; +#КонецЕсли + +КонецФункции + +#КонецОбласти + +#Область ВызовМетодов + +Функция ВыполнитьМетод(ПолноеИмяМетода, Параметры = Неопределено, Объект = Неопределено) Экспорт + +#Если ВебКлиент Тогда + ВызватьИсключение ЮТИсключения.МетодНеДоступен("ЮТОбщий.ВыполнитьМетод"); +#Иначе + Если СтрЗаканчиваетсяНа(ПолноеИмяМетода, ")") Тогда + + Алгоритм = ПолноеИмяМетода; + + ИначеЕсли НЕ ЗначениеЗаполнено(Параметры) Тогда + + Алгоритм = ПолноеИмяМетода + "()"; + + ИначеЕсли ТипЗнч(Параметры) = Тип("Массив") Тогда + + Алгоритм = СтрШаблон("%1(%2)", ПолноеИмяМетода, СтрокаПараметровМетода(Параметры, "Параметры")); + + Иначе + + ВызватьИсключение СтрШаблон("Не верный тип параметров `%1` для вызова метода, должен быть массив", ТипЗнч(Параметры)); + + КонецЕсли; + + Попытка + //@skip-check server-execution-safe-mode + Выполнить(Алгоритм); + Исключение + Возврат ИнформацияОбОшибке(); + КонецПопытки; + + Возврат Неопределено; +#КонецЕсли + +КонецФункции + +Функция ВычислитьБезопасно(Выражение) Экспорт + +#Если НЕ ВебКлиент И НЕ ТонкийКлиент Тогда + УстановитьБезопасныйРежим(Истина); + Попытка + Значение = Вычислить(Выражение); + Исключение + УстановитьБезопасныйРежим(Ложь); + ВызватьИсключение; + КонецПопытки; + + УстановитьБезопасныйРежим(Ложь); +#Иначе + Значение = Вычислить(Выражение); +#КонецЕсли + + Возврат Значение; + +КонецФункции + +#КонецОбласти + +#КонецОбласти + +#Область СлужебныеПроцедурыИФункции + +Функция ВерсияЗапретаИспользованияУстаревших() + + Возврат "23.01"; + +КонецФункции + +Функция СтрокаПараметровМетода(Параметры, ИмяПеременнойСПараметрами) + + СписокПараметров = Новый Массив(); + + Для Инд = 0 По Параметры.ВГраница() Цикл + + Если Параметры[Инд] = Мокито.ПараметрПоУмолчанию() Тогда + СписокПараметров.Добавить(""); + Иначе + СписокПараметров.Добавить(СтрШаблон("%1[%2]", ИмяПеременнойСПараметрами, Инд)); + КонецЕсли; + + КонецЦикла; + + Возврат СтрСоединить(СписокПараметров, ", "); + +КонецФункции + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТНастройкиВыполнения.xml b/src/cfe/YAXUnit/CommonModules/ЮТНастройкиВыполнения.xml new file mode 100644 index 0000000..8010ebe --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТНастройкиВыполнения.xml @@ -0,0 +1,23 @@ + + + + + ЮТНастройкиВыполнения + + + ru + Параметры + + + + false + true + true + false + true + false + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТНастройкиВыполнения/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТНастройкиВыполнения/Ext/Module.bsl new file mode 100644 index 0000000..56a39e6 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТНастройкиВыполнения/Ext/Module.bsl @@ -0,0 +1,121 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область ПрограммныйИнтерфейс + +// Возвращает значение настройки "ВТранзакции" для текущего исполняемого объекта (тест, набор, модуль) +// +// Возвращаемое значение: +// Булево +Функция ВТранзакции() Экспорт + + ИмяПараметра = ЮТФабрика.ПараметрыИсполненияТеста().ВТранзакции; + + Возврат ЗначениеНастройкиТеста(ИмяПараметра, Ложь); + +КонецФункции + +// Возвращает значение настройки "УдалениеТестовыхДанных" для текущего исполняемого объекта (тест, набор, модуль) +// +// Возвращаемое значение: +// Булево +Функция УдалениеТестовыхДанных() Экспорт + + ИмяПараметра = ЮТФабрика.ПараметрыИсполненияТеста().УдалениеТестовыхДанных; + + Возврат ЗначениеНастройкиТеста(ИмяПараметра, Ложь); + +КонецФункции + +// Возвращает значение настройки "Перед" для текущего исполняемого объекта (тест, набор, модуль) +// Возвращает имя назначенного обработчика события (имя метода) "Перед". +// +// Возвращаемое значение: +// Строка +Функция Перед() Экспорт + + ИмяПараметра = ЮТФабрика.ПараметрыИсполненияТеста().Перед; + + Возврат ЗначениеНастройкиТеста(ИмяПараметра, "", Истина); + +КонецФункции + +// Возвращает значение настройки "После" для текущего исполняемого объекта (тест, набор, модуль) +// Возвращает имя назначенного обработчика события (имя метода) "После". +// +// Возвращаемое значение: +// Строка +Функция После() Экспорт + + ИмяПараметра = ЮТФабрика.ПараметрыИсполненияТеста().После; + + Возврат ЗначениеНастройкиТеста(ИмяПараметра, "", Истина); + +КонецФункции + +// Возвращает значение произвольной настройки для текущего исполняемого объекта (тест, набор, модуль) +// +// Параметры: +// ИмяНастройки - Строка - Имя настройки, см. ЮТФабрика.ПараметрыИсполненияТеста +// ЗначениеПоУмолчанию - Произвольный - Значение по умолчанию +// СтрогийУровеньИсполнения - Булево - Признак, стоит ли проверять наличие настройки у родительских элементов. +// Ложь - По умолчанию, будет выполнен поиск и получение значения для родетелей (набор, модуль), если значения для текущего элемента не установлено. +// Истина - Получение настройки только для текущего элемента. +// +// Возвращаемое значение: +// Произвольный, Неопределено, Булево, Строка - Значение настройки теста +Функция ЗначениеНастройкиТеста(ИмяНастройки, ЗначениеПоУмолчанию, СтрогийУровеньИсполнения = Ложь) Экспорт + + Значение = ЗначениеПоУмолчанию; + КонтекстИсполнения = ЮТКонтекстСлужебный.КонтекстИсполнения(); + + Если СтрогийУровеньИсполнения Тогда + + ТекущийКонтекстИсполнения = ЮТКонтекстСлужебный.КонтекстИсполненияТекущегоУровня(); + + Если ТекущийКонтекстИсполнения <> Неопределено Тогда + Значение = ЮТКоллекции.ЗначениеСтруктуры(ТекущийКонтекстИсполнения.НастройкиВыполнения, ИмяНастройки, ЗначениеПоУмолчанию); + КонецЕсли; + + ИначеЕсли КонтекстИсполнения.Тест <> Неопределено И КонтекстИсполнения.Тест.НастройкиВыполнения.Свойство(ИмяНастройки) Тогда + + Значение = КонтекстИсполнения.Тест.НастройкиВыполнения[ИмяНастройки]; + + ИначеЕсли КонтекстИсполнения.Набор <> Неопределено И КонтекстИсполнения.Набор.НастройкиВыполнения.Свойство(ИмяНастройки) Тогда + + Значение = КонтекстИсполнения.Набор.НастройкиВыполнения[ИмяНастройки]; + + ИначеЕсли КонтекстИсполнения.Модуль <> Неопределено И КонтекстИсполнения.Модуль.НастройкиВыполнения.Свойство(ИмяНастройки) Тогда + + Значение = КонтекстИсполнения.Модуль.НастройкиВыполнения[ИмяНастройки]; + + Иначе + + ГлобальныеНастройки = ЮТКонтекстСлужебный.ГлобальныеНастройкиВыполнения(); + + Если ГлобальныеНастройки.Свойство(ИмяНастройки) Тогда + Значение = ГлобальныеНастройки[ИмяНастройки]; + КонецЕсли; + + КонецЕсли; + + Возврат Значение; + +КонецФункции + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТОбщий.xml b/src/cfe/YAXUnit/CommonModules/ЮТОбщий.xml new file mode 100644 index 0000000..8f5810e --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТОбщий.xml @@ -0,0 +1,23 @@ + + + + + ЮТОбщий + + + ru + Общий + + + Набор общих (во всех контекстах) методов + false + true + true + false + true + false + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТОбщий/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТОбщий/Ext/Module.bsl new file mode 100644 index 0000000..903abe0 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТОбщий/Ext/Module.bsl @@ -0,0 +1,890 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область ПрограммныйИнтерфейс + +// Возвращает значение свойства объекта. +// Возможно получение "глубоко" вложенных свойство и элементов коллекции по индексу +// +// Параметры: +// Объект - Произвольный +// ИмяСвойства - Строка - Путь к свойству. Примеры: "ИмяСвойства.ИмяВложенногоСвойства", "[2].ИмяСвойства", "ИмяСвойства[2].ИмяВложенногоСвойства" +// - Число - Индекс элемента. Возможен выбор элемента с конца, для этого нужно указывать отрицательный номер элемента с конца, +// например: '-1' - последний элемент, '-2' - предпоследний +// Возвращаемое значение: +// Произвольный +Функция ЗначениеСвойства(Объект, ИмяСвойства) Экспорт + + Путь = ЧастиПути(ИмяСвойства); + + Значение = Объект; + Для Каждого Часть Из Путь Цикл + + Если ТипЗнч(Значение) = Тип("ХранилищеЗначения") Тогда +#Если ВебКлиент Или ТонкийКлиент Тогда + Значение = ЮТОбщийСлужебныйВызовСервера.ИзХранилищаЗначений(Значение); +#Иначе + Значение = Значение.Получить(); +#КонецЕсли + КонецЕсли; + + Если ТипЗнч(Часть) = Тип("Число") И Часть < 0 И ТипЗнч(Значение) <> Тип("Соответствие") Тогда + Часть = Значение.Количество() + Часть; + КонецЕсли; + + Значение = Значение[Часть]; + + КонецЦикла; + + Возврат Значение; + +КонецФункции + +// Вычисляет хеш по алгоритму md5. +// +// Параметры: +// Данные - Строка, ДвоичныеДанные - Данные, для которых необходимо вычислить хеш +// +// Возвращаемое значение: +// Строка +Функция ХешMD5(Данные) Экспорт + + Возврат ЮТОбщийСлужебныйВызовСервера.ХешMD5(Данные); + +КонецФункции + +#Область ДатаВремя + +// Добавляет к дате указанное значение временных интервалов +// +// Параметры: +// Дата - Дата +// Интервал - Число - Добавляемое +// ТипИнтервала - Строка - Тип интервала +// +// Возвращаемое значение: +// Дата +Функция ДобавитьКДате(Дата, Интервал, ТипИнтервала) Экспорт + + Если ЭтоМесяц(ТипИнтервала) Тогда + Возврат ДобавитьМесяц(Дата, Интервал); + КонецЕсли; + + Множитель = МножительПериода(ТипИнтервала); + Возврат Дата + Множитель * Интервал; + +КонецФункции + +#КонецОбласти + +#КонецОбласти + +#Область СлужебныйПрограммныйИнтерфейс + +#Область Числа + +// Инкрементирует значение +// +// Параметры: +// Значение - Число +// Шаг - Число +// Возвращаемое значение: +// Число - Результат инкремента +Функция Инкремент(Значение, Знач Шаг = 1) Экспорт + + Значение = Значение + Шаг; + Возврат Значение; + +КонецФункции + +Функция ЧислоВСтроку(Значение) Экспорт + + Возврат Формат(Значение, "ЧН = 0; ЧГ="); + +КонецФункции + +#КонецОбласти + +#Область ДатаВремя + +// Человекочитаемое представление продолжительности +// +// Параметры: +// Продолжительность - Число - Продолжительность в миллисекундах +// +// Возвращаемое значение: +// Строка - Представление продолжительности +Функция ПредставлениеПродолжительности(Знач Продолжительность) Экспорт + + Представление = ЧислоВСтроку(Цел(Продолжительность / 1000)); + Представление = ЮТСтроки.ДобавитьСтроку(Представление, Формат(Продолжительность % 1000, "ЧЦ=3; ЧВН=;"), "."); + + Инкремент(Представление, " сек"); + + Возврат Представление; + +КонецФункции + +Функция ПредставлениеУниверсальнойДата(Знач УниверсальнаяДатаВМиллисекундах = Неопределено) Экспорт + + Если УниверсальнаяДатаВМиллисекундах = Неопределено Тогда + УниверсальнаяДатаВМиллисекундах = ТекущаяУниверсальнаяДатаВМиллисекундах(); + КонецЕсли; + + Дата = '00010101' + УниверсальнаяДатаВМиллисекундах / 1000; + Дата = МестноеВремя(Дата); + + Возврат СтрШаблон("%1.%2", Дата, Формат(УниверсальнаяДатаВМиллисекундах % 1000, "ЧЦ=3; ЧН=000; ЧВН=; ЧГ=0;")); + +КонецФункции + +#КонецОбласти + +#Область ЧтениеДанных + +Функция ДанныеТекстовогоФайла(ИмяФайла) Экспорт + +#Если НЕ ВебКлиент Тогда + Чтение = Новый ЧтениеТекста; + Чтение.Открыть(ИмяФайла, "UTF-8"); + Текст = Чтение.Прочитать(); + Чтение.Закрыть(); + + Возврат Текст; +#Иначе + ВызватьИсключение "Чтение данных текстовых файлов в веб-клиенте не поддерживается"; +#КонецЕсли + +КонецФункции + +Функция ЗначениеИзJSON(СтрокаJSON) Экспорт + +#Если НЕ ВебКлиент Тогда + Чтение = Новый ЧтениеJSON; + Чтение.УстановитьСтроку(СтрокаJSON); + Значение = ПрочитатьJSON(Чтение); + Чтение.Закрыть(); + Возврат Значение; +#Иначе + ВызватьИсключение "Разбор JSON строки в веб-клиенте не поддерживается"; +#КонецЕсли + +КонецФункции + +#КонецОбласти + +// ПеременнаяСодержитСвойство +// функция проверяет наличие свойства у значения любого типа данных. Если передано НЕОПРЕДЕЛЕНО, то ф-ия всегда вернет Ложь +// +// Параметры: +// Переменная - Произвольный - переменная любого типа, для которой необходимо проверить наличие свойства +// ИмяСвойства - Строка - переменная типа "Строка", содержащая искомое свойства +// +// Возвращаемое значение: +// Булево - признак наличия свойства у значения +// +Функция ПеременнаяСодержитСвойство(Переменная, ИмяСвойства) Экспорт + + Если Переменная = Неопределено Тогда + Возврат Ложь; + КонецЕсли; + + // Инициализируем структуру для теста с ключом (значение переменной "ИмяСвойства") и значением произвольного GUID'а + GUIDПроверка = Новый УникальныйИдентификатор; + СтруктураПроверка = Новый Структура; + СтруктураПроверка.Вставить(ИмяСвойства, GUIDПроверка); + // Заполняем созданную структуру из переданного значения переменной + ЗаполнитьЗначенияСвойств(СтруктураПроверка, Переменная); + // Если значение для свойства структуры осталось GUIDПроверка, то искомое свойство не найдено, и наоборот. + Возврат СтруктураПроверка[ИмяСвойства] <> GUIDПроверка; + +КонецФункции + +// СообщитьПользователю +// Формирует и выводит сообщение +// +// Параметры: +// ТекстСообщенияПользователю - Строка - текст сообщения. +Процедура СообщитьПользователю(ТекстСообщенияПользователю) Экспорт + + Сообщение = Новый СообщениеПользователю; + Сообщение.Текст = СокрЛП(ТекстСообщенияПользователю); + Сообщение.Сообщить(); + +КонецПроцедуры + +Функция СтрокаJSON(Значение, ИспользоватьСериализатор = Истина) Экспорт + +#Если ВебКлиент Тогда + ВызватьИсключение ЮТИсключения.МетодНеДоступен("ЮТОбщий.СтрокаJSON"); +#Иначе + ЗаписьJSON = Новый ЗаписьJSON(); + ЗаписьJSON.УстановитьСтроку(); + Если ИспользоватьСериализатор Тогда + //@skip-check undefined-variable + СериализаторXDTO.ЗаписатьJSON(ЗаписьJSON, Значение); + Иначе + ЗаписатьJSON(ЗаписьJSON, Значение); + КонецЕсли; + + Возврат ЗаписьJSON.Закрыть(); +#КонецЕсли + +КонецФункции // СтрокаJSON + +Функция ПредставлениеЗначения(Значение) Экспорт + + Попытка + Возврат СтрокаJSON(Значение); + Исключение + Возврат Строка(Значение); + КонецПопытки; + +КонецФункции + +// Параметры записи объекта +// +// Возвращаемое значение: +// Структура - Параметры записи: +// * ОбменДаннымиЗагрузка - Булево +// * ДополнительныеСвойства - Структура +// * РежимЗаписи - РежимЗаписиДокумента +// - Неопределено +Функция ПараметрыЗаписи() Экспорт + + ПараметрыЗаписи = Новый Структура(); + ПараметрыЗаписи.Вставить("ОбменДаннымиЗагрузка", Ложь); + ПараметрыЗаписи.Вставить("ДополнительныеСвойства", Новый Структура); + ПараметрыЗаписи.Вставить("РежимЗаписи", Неопределено); + + Возврат ПараметрыЗаписи; + +КонецФункции + +Функция УстановленБезопасныйРежим() Экспорт + + Возврат ЮТОбщийСлужебныйВызовСервера.УстановленБезопасныйРежим(); + +КонецФункции + +Функция МестноеВремяПоВременнойМетке(Метка) Экспорт + + Если ЗначениеЗаполнено(Метка) Тогда + Возврат МестноеВремя('00010101' + Метка / 1000); + Иначе + Возврат Неопределено; + КонецЕсли; + +КонецФункции + +Функция ПродолжительностьВСекундах(Продолжительность) Экспорт + + Возврат Продолжительность / 1000; + +КонецФункции + +Функция Модуль(ИмяМодуля) Экспорт + + Возврат ЮТМетодыСлужебный.ВычислитьБезопасно(ИмяМодуля); + +КонецФункции + +Функция Менеджер(Знач Менеджер) Экспорт + +#Если Сервер Тогда + Возврат ЮТОбщийСлужебныйВызовСервера.Менеджер(Менеджер); +#Иначе + ВызватьИсключение ЮТИсключения.МетодНеДоступен("ЮТОбщий.Менеджер", "клиенте"); +#КонецЕсли + +КонецФункции + +Функция ТипСтруктуры(Структура) Экспорт + + Возврат ЮТКоллекции.ЗначениеСтруктуры(Структура, "__type__"); + +КонецФункции + +Функция ЭтаСтруктураИмеетТип(Структура, ИмяТипа) Экспорт + + Возврат ТипСтруктуры(Структура) = ИмяТипа; + +КонецФункции + +Процедура УказатьТипСтруктуры(Структура, ИмяТипа) Экспорт + + Структура.Вставить("__type__", ИмяТипа); + +КонецПроцедуры + +// Преостанавливает поток выполнения на указанное количество секунд +// +// Параметры: +// Время - Число - Продолжительность паузы в секундах, возможно указывать дробное значение +Процедура Пауза(Время) Экспорт + + Задержка = Цел(1000 * Время); + Компонента = ЮТКомпоненты.Пауза(); +#Если Сервер Тогда + Компонента.Ожидать(Задержка); +#Иначе + Если ЮТМетаданные.РазрешеныСинхронныеВызовы() Тогда + Компонента.Ожидать(Задержка); + Иначе + ВызватьИсключение "Пауза не работает на клиенте при отключенных синхронных вызовах"; + КонецЕсли; +#КонецЕсли + +КонецПроцедуры + +// Выводит сообщение в консоль (stdout) приложения +// +// Параметры: +// Сообщение - Строка - Выводимое сообщение +Процедура ВывестиВКонсоль(Сообщение) Экспорт + + Компонента = ЮТКомпоненты.Консоль(); +#Если Сервер Тогда + Компонента.Напечатать(Сообщение); +#Иначе + Если ЮТМетаданные.РазрешеныСинхронныеВызовы() Тогда + Компонента.Напечатать(Сообщение); + Иначе + Компонента.НачатьВызовНапечатать(ЮТАсинхроннаяОбработкаСлужебныйКлиент.НовыйПустойОбработчик(3), Сообщение); + КонецЕсли; +#КонецЕсли + +КонецПроцедуры + +// Возвращяет макет +// +// Параметры: +// ИмяМакета - Строка - Возможные значения +// * Общий макет, например, ОбщийМакет.ЮТМетаданные +// * Макет объекта метаданных, например, Справочник.Товары.ПечатнаяФорма +// * Область макета, например, Справочник.Товары.ПечатнаяФорма.Шапка, ОбщийМакет.ЮТМетаданные.Заголовок +// +// Возвращаемое значение: +// ТабличныйДокумент, ТекстовыйДокумент, ДвоичныеДанные - Макет или его область +Функция Макет(ИмяМакета) Экспорт + + Возврат ЮТОбщийСлужебныйВызовСервера.Макет(ИмяМакета); + +КонецФункции + +#Область УстаревшиеПроцедурыИФункции + +// Устарела. Метод перенесен в см. ЮТСтроки.ДобавитьСтроку +// Конкатенирует строки, разделяя их разделителем +// +// Параметры: +// ИсходнаяСтрока - Строка - Исходная строка +// ДополнительнаяСтрока - Строка - Добавляемая строка +// Разделитель - Строка - Строка разделитель, любой набор символов - разделитель между подстроками +// +// Возвращаемое значение: +// Строка - Результат конкатенации строк +Функция ДобавитьСтроку(ИсходнаяСтрока, ДополнительнаяСтрока, Разделитель = ";") Экспорт + + ЮТМетодыСлужебный.ВызовУстаревшегоМетода("ЮТОбщий.ДобавитьСтроку", "ЮТСтроки.ДобавитьСтроку", "24.03"); + Возврат ЮТСтроки.ДобавитьСтроку(ИсходнаяСтрока, ДополнительнаяСтрока, Разделитель); + +КонецФункции + +// Устарела. Метод перенесен в см. ЮТСтроки.РазделитьСтроку +// Возвращает массив на основании строки +// +// Параметры: +// Значение - Строка - преобразуемая строка +// Разделитель - Строка - строка-разделитель +// +// Возвращаемое значение: +// Массив Из Строка - массив строк +// +Функция РазложитьСтрокуВМассивПодстрок(Значение, Разделитель = ";") Экспорт + + ЮТМетодыСлужебный.ВызовУстаревшегоМетода("ЮТОбщий.РазложитьСтрокуВМассивПодстрок", "ЮТСтроки.РазбитьСтроку", "24.03"); + Возврат ЮТСтроки.РазделитьСтроку(Значение, Разделитель); + +КонецФункции + +// Устарела. Метод перенесен в см. ЮТСтроки.СтрокаСимволов +// Формирует строку из заданного количества повторяемых символов +// Параметры: +// Символ - Строка - Повторяемый символ +// Количество - Число - Количество повторений +// +// Возвращаемое значение: +// Строка - Строка повторяемых символов +Функция СформироватьСтрокуСимволов(Символ, Количество) Экспорт + + ЮТМетодыСлужебный.ВызовУстаревшегоМетода("ЮТОбщий.СформироватьСтрокуСимволов", "ЮТСтроки.СтрокаСимволов", "24.03"); + Возврат ЮТСтроки.СтрокаСимволов(Символ, Количество); + +КонецФункции + +// Устарела. Метод перенесен в см. ЮТКоллекции.ЗначениеСтруктуры +// Возвращает требуемое поле структуры. В случае отсутствия поля возвращает значение по умолчанию +// +// Параметры: +// ИсходнаяСтруктура - Структура - Исходная структура +// ИмяПоля - Строка - Имя поля структуры +// ЗначениеПоУмолчанию - Произвольный - Значение, которое будет возвращено, если поля в структуре нет +// +// Возвращаемое значение: +// Произвольный - Значение искомого поля структуры +Функция ЗначениеСтруктуры(ИсходнаяСтруктура, ИмяПоля, ЗначениеПоУмолчанию = Неопределено) Экспорт + + ЮТМетодыСлужебный.ВызовУстаревшегоМетода("ЮТОбщий.ЗначениеСтруктуры", "ЮТКоллекции.ЗначениеСтруктуры", "24.03"); + Возврат ЮТКоллекции.ЗначениеСтруктуры(ИсходнаяСтруктура, ИмяПоля, ЗначениеПоУмолчанию); + +КонецФункции + +// Устарела. Метод перенесен в см. ЮТКоллекции.ДополнитьСтруктуру +// Функция, объединяющая две коллекции( с типами Структура или Соответствие) в одну структуру, если это возможно +// +// Параметры: +// Коллекция1 - Соответствие из Произвольный +// - Структура +// Коллекция2 - Соответствие из Произвольный +// - Структура +// +// Возвращаемое значение: +// Структура - Результат объединения двух коллекций +// +Функция ОбъединитьВСтруктуру(Знач Коллекция1, Коллекция2) Экспорт + + ЮТМетодыСлужебный.ВызовУстаревшегоМетода("ЮТОбщий.ОбъединитьВСтруктуру", "ЮТКоллекции.ДополнитьСтруктуру", "24.03"); + Если ТипЗнч(Коллекция1) <> Тип("Структура") Тогда + Коллекция1 = ЮТКоллекции.СкопироватьСтруктуру(Коллекция1); + КонецЕсли; + + ЮТКоллекции.ДополнитьСтруктуру(Коллекция1, Коллекция2); + + //@skip-check constructor-function-return-section + Возврат Коллекция1; + +КонецФункции + +// Устарела. Метод перенесен в см. ЮТКоллекции.СкопироватьРекурсивно +// Создает копию экземпляра указанного объекта. +// Примечание: +// Функцию нельзя использовать для объектных типов (СправочникОбъект, ДокументОбъект и т.п.). +// +// Параметры: +// Источник - Произвольный - объект, который необходимо скопировать. +// +// Возвращаемое значение: +// Произвольный - копия объекта, переданного в параметре Источник. +// +Функция СкопироватьРекурсивно(Источник) Экспорт + + ЮТМетодыСлужебный.ВызовУстаревшегоМетода("ЮТОбщий.СкопироватьРекурсивно", "ЮТКоллекции.СкопироватьРекурсивно", "24.03"); + Возврат ЮТКоллекции.СкопироватьРекурсивно(Источник); + +КонецФункции + +// Устарела. Метод перенесен в см. ЮТКоллекции.СкопироватьСтруктуру +// Создает копию значения типа Структура +// +// Параметры: +// Источник - Структура - копируемая структура +// +// Возвращаемое значение: +// Структура - копия исходной структуры. +// +Функция СкопироватьСтруктуру(Источник) Экспорт + + ЮТМетодыСлужебный.ВызовУстаревшегоМетода("ЮТОбщий.СкопироватьСтруктуру", "ЮТКоллекции.СкопироватьСтруктуру", "24.03"); + Возврат ЮТКоллекции.СкопироватьСтруктуру(Источник); + +КонецФункции + +// Устарела. Метод перенесен в см. ЮТКоллекции.СкопироватьСоответствие +// Создает копию значения типа Соответствие. +// +// Параметры: +// Источник - Соответствие из Произвольный - соответствие, копию которого необходимо получить. +// +// Возвращаемое значение: +// Соответствие Из Произвольный - копия исходного соответствия. +// +Функция СкопироватьСоответствие(Источник) Экспорт + + ЮТМетодыСлужебный.ВызовУстаревшегоМетода("ЮТОбщий.СкопироватьСоответствие", "ЮТКоллекции.СкопироватьСоответствие", "24.03"); + Возврат ЮТКоллекции.СкопироватьСоответствие(Источник); + +КонецФункции + +// Устарела. Метод перенесен в см. ЮТКоллекции.СкопироватьМассив +// Создает копию значения типа Массив. +// +// Параметры: +// Источник - Массив Из Произвольный - массив, копию которого необходимо получить +// +// Возвращаемое значение: +// Массив Из Произвольный - копия исходного массива. +// +Функция СкопироватьМассив(Источник) Экспорт + + ЮТМетодыСлужебный.ВызовУстаревшегоМетода("ЮТОбщий.СкопироватьМассив", "ЮТКоллекции.СкопироватьМассив", "24.03"); + Возврат ЮТКоллекции.СкопироватьМассив(Источник); + +КонецФункции + +// Устарела. Метод перенесен в см. ЮТКоллекции.СкопироватьСписокЗначений +// Создает копию значения типа СписокЗначений. +// +// Параметры: +// Источник - СписокЗначений Из Произвольный - список значений, копию которого необходимо получить +// +// Возвращаемое значение: +// СписокЗначений Из Произвольный - копия исходного списка значений +// +Функция СкопироватьСписокЗначений(Источник) Экспорт + + ЮТМетодыСлужебный.ВызовУстаревшегоМетода("ЮТОбщий.СкопироватьСписокЗначений", "ЮТКоллекции.СкопироватьСписокЗначений", "24.03"); + Возврат ЮТКоллекции.СкопироватьСписокЗначений(Источник); + +КонецФункции + +// Устарела. Метод перенесен в см. ЮТКоллекции.ВыгрузитьЗначения +// +// Параметры: +// Коллекция - Произвольный +// ИмяРеквизита - Строка +// +// Возвращаемое значение: +// Массив из Произвольный - Выгрузить значения +Функция ВыгрузитьЗначения(Коллекция, ИмяРеквизита) Экспорт + + ЮТМетодыСлужебный.ВызовУстаревшегоМетода("ЮТОбщий.ВыгрузитьЗначения", "ЮТКоллекции.ВыгрузитьЗначения", "24.03"); + Возврат ЮТКоллекции.ВыгрузитьЗначения(Коллекция, ИмяРеквизита); + +КонецФункции + +// Устарела. Метод перенесен в см. ЮТКоллекции.ВыгрузитьЗначения +// +// Параметры: +// Коллекция1 - Массив из Произвольный +// Коллекция2 - Массив из Произвольный +// +// Возвращаемое значение: +// Массив из Произвольный - Пересечение массивов +Функция ПересечениеМассивов(Коллекция1, Коллекция2) Экспорт + + ЮТМетодыСлужебный.ВызовУстаревшегоМетода("ЮТОбщий.ПересечениеМассивов", "ЮТКоллекции.ПересечениеМассивов", "24.03"); + Возврат ЮТКоллекции.ПересечениеМассивов(Коллекция1, Коллекция2); + +КонецФункции + +// Устарела. Метод перенесен в см. ЮТКоллекции.ЗначениеВМассиве +// Создает массив с переданными значениями +// +// Параметры: +// Значение - Произвольный +// Значение2 - Произвольный +// Значение3 - Произвольный +// Значение4 - Произвольный +// Значение5 - Произвольный +// Значение6 - Произвольный +// Значение7 - Произвольный +// Значение8 - Произвольный +// Значение9 - Произвольный +// Значение10 - Произвольный +// +// Возвращаемое значение: +// Массив из Произвольный +//@skip-check method-too-many-params +Функция ЗначениеВМассиве(Значение, + Значение2 = "_!%*", + Значение3 = "_!%*", + Значение4 = "_!%*", + Значение5 = "_!%*", + Значение6 = "_!%*", + Значение7 = "_!%*", + Значение8 = "_!%*", + Значение9 = "_!%*", + Значение10 = "_!%*") Экспорт + + ЮТМетодыСлужебный.ВызовУстаревшегоМетода("ЮТОбщий.ЗначениеВМассиве", "ЮТКоллекции.ЗначениеВМассиве", "24.03"); + Возврат ЮТКоллекции.ЗначениеВМассиве(Значение, Значение2, Значение3, Значение4, Значение5, Значение6, Значение7, Значение8, Значение9, Значение10); + +КонецФункции + +// Устарела. Метод перенесен в см. ЮТКоллекции.ДополнитьМассив +// +// Параметры: +// Приемник - Массив из Произвольный +// Источник - Массив из Произвольный +Процедура ДополнитьМассив(Приемник, Источник) Экспорт + + ЮТМетодыСлужебный.ВызовУстаревшегоМетода("ЮТОбщий.ДополнитьМассив", "ЮТКоллекции.ДополнитьМассив", "24.03"); + ЮТКоллекции.ДополнитьМассив(Приемник, Источник); + +КонецПроцедуры + +// Устарела. Метод перенесен в см. ЮТКоллекции.ВСоответствие +// Возвращает соответствие элементов переданной коллекции, в качестве ключей выступают значения указанного поля элементов коллекции. +// +// Параметры: +// Коллекция - Произвольный - значение, для которого определен итератор, и возможно обращение к полям элементов через квадратные скобки. +// ИмяПоляКлюча - Строка - имя поля элемента коллекции, которое будет ключом соответствия. +// ИмяПоляЗначения - Строка - если указан, значениями результата будут не элементы, а значения соответствующих полей элементов коллекции. +// Возвращаемое значение: +// Соответствие Из Произвольный - полученное соответствие. +Функция ВСоответствие(Коллекция, ИмяПоляКлюча, ИмяПоляЗначения = Неопределено) Экспорт + + ЮТМетодыСлужебный.ВызовУстаревшегоМетода("ЮТОбщий.ВСоответствие", "ЮТКоллекции.ВСоответствие", "24.03"); + Возврат ЮТКоллекции.ВСоответствие(Коллекция, ИмяПоляКлюча, ИмяПоляЗначения); + +КонецФункции + +// Устарела. Метод перенесен в см. ЮТКоллекции.ВСтруктуру +// Возвращает структуру элементов переданной коллекции, в качестве ключей выступают значения указанного поля элементов коллекции. +// +// Параметры: +// Коллекция - Произвольный - значение, для которого определен итератор, и возможно обращение к полям элементов через квадратные скобки. +// ИмяПоляКлюча - Строка - имя поля элемента коллекции, которое будет ключом соответствия. +// ИмяПоляЗначения - Строка - если указан, значениями результата будут не элементы, а значения соответствующих полей элементов коллекции. +// Возвращаемое значение: +// Структура Из Произвольный - полученная структура. +Функция ВСтруктуру(Коллекция, ИмяПоляКлюча, ИмяПоляЗначения = Неопределено) Экспорт + + ЮТМетодыСлужебный.ВызовУстаревшегоМетода("ЮТОбщий.ВСтруктуру", "ЮТКоллекции.ВСтруктуру", "24.03"); + Возврат ЮТКоллекции.ВСтруктуру(Коллекция, ИмяПоляКлюча, ИмяПоляЗначения); + +КонецФункции + +// Устарела. МетодМодуляСуществует +// Проверяет существование публичного (экспортного) метода у модуля +// +// Параметры: +// ИмяМодуля - Строка - Имя модуля, метод которого нужно поискать +// ИмяМетода - Строка - Имя метода, который ищем +// КоличествоПараметров - Число - Количество параметров метода, увы это никак не влияет на проверку +// Кешировать - Булево - Признак кеширования результата проверки +// +// Возвращаемое значение: +// Булево - Метод найден +Функция МетодМодуляСуществует(ИмяМодуля, ИмяМетода, КоличествоПараметров = 0, Кешировать = Истина) Экспорт + + ЮТМетодыСлужебный.ВызовУстаревшегоМетода("ЮТОбщий.МетодМодуляСуществует", Неопределено, "24.03"); + Возврат ЮТМетодыСлужебный.МетодМодуляСуществует(ИмяМодуля, ИмяМетода, Кешировать); + +КонецФункции + +// Устарела. Проверяет существование публичного (экспортного) метода у объекта +// +// Параметры: +// Объект - Произвольный - Объект, метод которого нужно поискать +// ИмяМетода - Строка - Имя метода, который ищем +// +// Возвращаемое значение: +// Булево - Метод найден +Функция МетодОбъектаСуществует(Объект, ИмяМетода) Экспорт + + ЮТМетодыСлужебный.ВызовУстаревшегоМетода("ЮТОбщий.МетодОбъектаСуществует", Неопределено, "24.03"); + Возврат ЮТМетодыСлужебный.МетодОбъектаСуществует(Объект, ИмяМетода); + +КонецФункции + +// Устарела. +Функция ВыполнитьМетод(ПолноеИмяМетода, Параметры = Неопределено, Объект = Неопределено) Экспорт + + ЮТМетодыСлужебный.ВызовУстаревшегоМетода("ЮТОбщий.ВыполнитьМетод", Неопределено, "24.03"); + Возврат ЮТМетодыСлужебный.ВыполнитьМетод(ПолноеИмяМетода, Параметры, Объект); + +КонецФункции + +// Устарела. +Функция ВычислитьБезопасно(Выражение) Экспорт + + ЮТМетодыСлужебный.ВызовУстаревшегоМетода("ЮТОбщий.ВычислитьБезопасно", Неопределено, "24.03"); + Возврат ЮТМетодыСлужебный.ВычислитьБезопасно(Выражение); + +КонецФункции + +// Устарела. +Функция ПредставлениеТипа(Тип) Экспорт + + ЮТМетодыСлужебный.ВызовУстаревшегоМетода("ЮТОбщий.ПредставлениеТипа", Неопределено, "24.03"); + Возврат ЮТТипыДанныхСлужебный.ПредставлениеТипа(Тип); + +КонецФункции + +// Устарела. Описание типов любая ссылка. +// +// Возвращаемое значение: +// ОписаниеТипов - Описание типов любая ссылка +Функция ОписаниеТиповЛюбаяСсылка() Экспорт + + ЮТМетодыСлужебный.ВызовУстаревшегоМетода("ЮТОбщий.ОписаниеТиповЛюбаяСсылка", Неопределено, "24.03"); + Возврат ЮТТипыДанныхСлужебный.ОписаниеТиповЛюбаяСсылка(); + +КонецФункции + +#КонецОбласти + +#КонецОбласти + +#Область СлужебныеПроцедурыИФункции + +Функция ПредставлениеОбъекта(Объект, Знач Уровень = 1, ПредставлениеОбъекта = Неопределено) + + ТипОбъекта = ТипЗнч(Объект); + + Шаблон = "%1 (%2)"; + Представление = ""; + ПредставлениеТипа = ТипОбъекта; + + Если ТипОбъекта = Тип("Структура") ИЛИ ТипОбъекта = Тип("Соответствие") Тогда + ЮТСтроки.СтрокаСимволов(" ", Уровень * 4); + Шаблон = "%2: + |%1"; + Представление = ЮТСтроки.СтрокаСимволов(" ", Уровень * 4) + ПредставлениеСтруктуры(Объект, Уровень); + + ИначеЕсли ТипОбъекта = Тип("Массив") Тогда + + Шаблон = "[%1] (%2)"; + Представление = СтрСоединить(Объект, ", "); + + ИначеЕсли ТипОбъекта = Тип("Число") Тогда + + Представление = ЧислоВСтроку(Объект); + + ИначеЕсли ТипОбъекта = Тип("Дата") Тогда + + Представление = Формат(Объект, "ДФ=""dd.MM.yyyy ЧЧ:мм:сс"""); + + ИначеЕсли ТипОбъекта = Тип("Булево") Тогда + + Представление = Строка(Объект); + + ИначеЕсли ТипОбъекта = Тип("Строка") Тогда + + Представление = Объект; + + Иначе + + Представление = Строка(Объект); + ПредставлениеТипа = ПредставлениеТипа(ТипОбъекта); // Для ссылочных + + КонецЕсли; + + Если ПустаяСтрока(Представление) Тогда + + Представление = "<Пусто>"; + + КонецЕсли; + + Возврат СтрШаблон(Шаблон, Представление, ?(ПредставлениеОбъекта = Неопределено, ПредставлениеТипа, ПредставлениеОбъекта)); + +КонецФункции + +Функция ПредставлениеСтруктуры(Значение, Уровень) + + Строки = Новый Массив(); + + Для Каждого Элемент Из Значение Цикл + + Строки.Добавить(СтрШаблон("%1: %2", Элемент.Ключ, ПредставлениеОбъекта(Элемент.Значение, Уровень + 1))); + + КонецЦикла; + + Возврат СтрСоединить(Строки, Символы.ПС + ЮТСтроки.СтрокаСимволов(" ", Уровень * 4)); + +КонецФункции + +Функция ЧастиПути(Цепочка) Экспорт + + ПутьКСвойству = Новый Массив(); + + ТипПути = ТипЗнч(Цепочка); + + Если ТипПути = Тип("Строка") Тогда + + Части = СтрРазделить(Цепочка, "."); + + Для Каждого Часть Из Части Цикл + + Если СодержитИндекс(Часть) Тогда + + ИзвлечьИндекс(Часть, ПутьКСвойству); + + Иначе + + ПутьКСвойству.Добавить(Часть); + + КонецЕсли; + + КонецЦикла; + + Иначе + + ПутьКСвойству.Добавить(Цепочка); + + КонецЕсли; // BSLLS:IfElseIfEndsWithElse-off + + Возврат ПутьКСвойству; + +КонецФункции + +Функция СодержитИндекс(ИмяСвойства) + + Возврат СтрНайти(ИмяСвойства, "[") > 0 И СтрЗаканчиваетсяНа(ИмяСвойства, "]"); + +КонецФункции + +Процедура ИзвлечьИндекс(ИмяСвойства, БлокиПути) + + ПозицияИндекса = СтрНайти(ИмяСвойства, "["); + + Если ПозицияИндекса > 1 Тогда + БлокиПути.Добавить(Лев(ИмяСвойства, ПозицияИндекса - 1)); + КонецЕсли; + + Пока ПозицияИндекса > 0 Цикл + + ЗакрывающаяПозиция = СтрНайти(ИмяСвойства, "]", , ПозицияИндекса); + ИндексСтрокой = Сред(ИмяСвойства, ПозицияИндекса + 1, ЗакрывающаяПозиция - ПозицияИндекса - 1); + Индекс = Число(ИндексСтрокой); + БлокиПути.Добавить(Индекс); + + ПозицияИндекса = СтрНайти(ИмяСвойства, "[", , ЗакрывающаяПозиция); + + КонецЦикла; + +КонецПроцедуры + +Функция МножительПериода(ТипИнтервала) + + Множители = ЮТСлужебныйПовторногоИспользования.МножителиИнтервалов(); + Возврат Множители[ТипИнтервала]; + +КонецФункции + +Функция ЭтоМесяц(ТипИнтервала) + + Возврат СтрСравнить(ТипИнтервала, "месяц") = 0 + ИЛИ СтрСравнить(ТипИнтервала, "месяца") = 0 + ИЛИ СтрСравнить(ТипИнтервала, "месяцев") = 0; + +КонецФункции + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТОбщийСлужебныйВызовСервера.xml b/src/cfe/YAXUnit/CommonModules/ЮТОбщийСлужебныйВызовСервера.xml new file mode 100644 index 0000000..2722f45 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТОбщийСлужебныйВызовСервера.xml @@ -0,0 +1,23 @@ + + + + + ЮТОбщийСлужебныйВызовСервера + + + ru + Общий (вызов сервера) + + + + false + false + true + false + true + true + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТОбщийСлужебныйВызовСервера/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТОбщийСлужебныйВызовСервера/Ext/Module.bsl new file mode 100644 index 0000000..6cb2a1c --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТОбщийСлужебныйВызовСервера/Ext/Module.bsl @@ -0,0 +1,147 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область СлужебныйПрограммныйИнтерфейс + +Функция ОписаниеТиповЛюбаяСсылка() Экспорт + + ЧтениеXML = Новый ЧтениеXML; + ЧтениеXML.УстановитьСтроку( + " + | cc:AnyRef + |"); + + Возврат СериализаторXDTO.ПрочитатьXML(ЧтениеXML); + +КонецФункции + +Функция УстановленБезопасныйРежим() Экспорт + + Возврат БезопасныйРежим(); + +КонецФункции + +Функция Менеджер(Знач Менеджер) Экспорт + + Описание = ЮТМетаданные.ОписаниеОбъектаМетаданных(Менеджер); + + Если Описание = Неопределено Тогда + ВызватьИсключение "Несуществующий объект метаданных, либо " + + ЮТИсключения.НеподдерживаемыйПараметрМетода("ЮТОбщийВызовСервера.Менеджер", Менеджер); + КонецЕсли; + + ИмяТипа = ""; + Если ЭтоАнглийскийВстроенныйЯзык() Тогда + ИмяТипа = СтрШаблон("%1Manager.%2", Описание.ОписаниеТипа.Имя, Описание.Имя); + Иначе + ИмяТипа = СтрШаблон("%1Менеджер.%2", Описание.ОписаниеТипа.Имя, Описание.Имя); + КонецЕсли; + + Возврат Новый(ИмяТипа); + +КонецФункции + +Функция Макет(ИмяМакета) Экспорт + + ЧастиИмени = СтрРазделить(ИмяМакета, "."); + + КоличествоБлоковДляОбщегоМакета = 2; + КоличествоБлоковМакетаМенеджера = 3; + + Если ЧастиИмени.Количество() < КоличествоБлоковДляОбщегоМакета Тогда + ВызватьИсключение СтрШаблон("Некорректное имя макет, если вы хотите получить данные общего макета необходимо указать `ОбщийМакет.%1`", + ИмяМакета); + КонецЕсли; + + ИндексОбласти = 0; + Если СтрСравнить(ЧастиИмени[0], "ОбщийМакет") = 0 Тогда + Макет = ПолучитьОбщийМакет(ЧастиИмени[1]); + ИндексОбласти = КоличествоБлоковДляОбщегоМакета; + ИначеЕсли ЧастиИмени.Количество() >= КоличествоБлоковМакетаМенеджера Тогда + Менеджер = Менеджер(СтрШаблон("%1.%2", ЧастиИмени[0], ЧастиИмени[1])); + Макет = Менеджер.ПолучитьМакет(ЧастиИмени[КоличествоБлоковМакетаМенеджера - 1]); + ИндексОбласти = КоличествоБлоковМакетаМенеджера; + Иначе + ВызватьИсключение СтрШаблон("Некорректное имя макета `%1`", ИмяМакета); + КонецЕсли; + + Если ЧастиИмени.Количество() > ИндексОбласти Тогда + Макет = Макет.ПолучитьОбласть(ЧастиИмени[ИндексОбласти]); + КонецЕсли; + + Возврат Макет; + +КонецФункции + +Функция ВыборкаИзТабличногоДокумента(ТабличныйДокумент) Экспорт + + Возврат ЗапросКТабличномуДокументу(ТабличныйДокумент).Выбрать(); + +КонецФункции + +Функция ТаблицаИзТабличногоДокумента(ТабличныйДокумент) Экспорт + + Возврат ЗапросКТабличномуДокументу(ТабличныйДокумент).Выгрузить(); + +КонецФункции + +Функция ИзХранилищаЗначений(Знач ХранилищеЗначений) Экспорт + Возврат ХранилищеЗначений.Получить(); +КонецФункции + +Функция ЭтоАнглийскийВстроенныйЯзык() Экспорт + + Возврат ЮТМетаданныеСлужебныйПовтИсп.ВариантВстроенногоЯзыка() = "English"; + +КонецФункции + +Функция ЭтоРусскийВстроенныйЯзык() Экспорт + + Возврат ЮТМетаданныеСлужебныйПовтИсп.ВариантВстроенногоЯзыка() = "Русский"; + +КонецФункции + +Функция ХешMD5(Строка) Экспорт + + Хеш = Новый ХешированиеДанных(ХешФункция.MD5); + Хеш.Добавить(Строка); + Возврат НРег(СтрЗаменить(Хеш.ХешСумма, " ", "")); + +КонецФункции + +#КонецОбласти + +#Область СлужебныеПроцедурыИФункции + +Функция ЗапросКТабличномуДокументу(ТабличныйДокумент) + + ВсегоСтрок = ТабличныйДокумент.ВысотаТаблицы; + ВсегоКолонок = ТабличныйДокумент.ШиринаТаблицы; + + Область = ТабличныйДокумент.Область(1, 1, ВсегоСтрок, ВсегоКолонок); + + ИсточникДанных = Новый ОписаниеИсточникаДанных(Область); + ПостроительОтчета = Новый ПостроительОтчета; + ПостроительОтчета.ИсточникДанных = ИсточникДанных; + ПостроительОтчета.Выполнить(); + + Возврат ПостроительОтчета.Результат; + +КонецФункции + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТОтчетAllureСлужебный.xml b/src/cfe/YAXUnit/CommonModules/ЮТОтчетAllureСлужебный.xml new file mode 100644 index 0000000..9e44fbc --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТОтчетAllureСлужебный.xml @@ -0,0 +1,23 @@ + + + + + ЮТОтчетAllureСлужебный + + + ru + Отчет allure + + + + false + true + false + false + true + false + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТОтчетAllureСлужебный/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТОтчетAllureСлужебный/Ext/Module.bsl new file mode 100644 index 0000000..4107e7a --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТОтчетAllureСлужебный/Ext/Module.bsl @@ -0,0 +1,266 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область СлужебныйПрограммныйИнтерфейс + +Функция ПараметрыГенерацииОтчета() Экспорт + + Параметры = ЮТФабрикаСлужебный.ПараметрыГенератораОтчета(); + + ОписаниеФормата = ЮТФабрикаСлужебный.ОписаниеФорматаОтчета("allure", "Allure 2 (json)"); + ОписаниеФормата.ЗаписьВКаталог = Истина; + ОписаниеФормата.СамостоятельнаяЗаписьОтчета = Истина; + Параметры.Форматы.Вставить(ОписаниеФормата.Идентификатор, ОписаниеФормата); + + Возврат Параметры; + +КонецФункции + +Процедура ЗаписатьОтчет(РезультатВыполнения, Каталог, Формат, Обработчик) Экспорт + +#Если ВебКлиент Тогда + ВызватьИсключение "Формирование отчета в формате Allure не поддерживается в web-клиенте"; +#Иначе + Для Каждого Модуль Из РезультатВыполнения Цикл + + Для Каждого Набор Из Модуль.НаборыТестов Цикл + + Для Каждого РезультатТеста Из Набор.Тесты Цикл + + Попытка + СохранитьОтчетТеста(РезультатТеста, Набор, Модуль, Каталог); + Исключение + ЮТЛогирование.Ошибка("Ошибка сохранения отчета в формате Allure. " + ПодробноеПредставлениеОшибки(ИнформацияОбОшибке())); + КонецПопытки; + + КонецЦикла; + + КонецЦикла; + + КонецЦикла; +#КонецЕсли + + ЮТАсинхроннаяОбработкаСлужебныйКлиент.ВызватьОбработчик(Обработчик); +КонецПроцедуры + +#КонецОбласти + +#Область СлужебныеПроцедурыИФункции + +#Если НЕ ВебКлиент Тогда +Процедура СохранитьОтчетТеста(РезультатТеста, Набор, Модуль, Каталог) + + Описание = ОписаниеТеста(РезультатТеста, Набор, Модуль); + + ИмяФайла = ЮТФайлы.ОбъединитьПути(Каталог, Описание.uuid + "-result.json"); + Запись = Новый ЗаписьJSON(); + Запись.ОткрытьФайл(ИмяФайла, КодировкаТекста.UTF8, Ложь); + ЗаписатьJSON(Запись, Описание); + Запись.Закрыть(); + +КонецПроцедуры + +Функция ОписаниеТеста(РезультатТеста, Набор, Модуль) Экспорт + + Статусы = ЮТФабрика.СтатусыИсполненияТеста(); + ПредставлениеРежима = СтрШаблон(" [%1]", РезультатТеста.Режим); + ПолныйИдентификаторТеста = СтрШаблон("%1_%2_%3", РезультатТеста.НомерВНаборе, РезультатТеста.ПолноеИмяМетода, РезультатТеста.Режим); + + Описание = НовыйОписаниеТеста(); + Описание.fullName = РезультатТеста.ПолноеИмяМетода + ПредставлениеРежима; + Описание.name = РезультатТеста.Метод + ПредставлениеРежима; + Описание.status = СтатусОтчета(РезультатТеста.Статус, Статусы); + Описание.testCaseId = ЮТОбщий.ХешMD5(ПолныйИдентификаторТеста); + Описание.start = РезультатТеста.ДатаСтарта; + Описание.stop = РезультатТеста.ДатаСтарта + РезультатТеста.Длительность; + + ОписаниеМодуля = ИмяМодуляПоСхеме(Модуль.МетаданныеМодуля.Имя); + ИмяНабора = Модуль.МетаданныеМодуля.Имя; + ИмяВложенногоНабора = Набор.Представление + ПредставлениеРежима; + + ДобавитьМетку(Описание, "language", "bsl"); + ДобавитьМетку(Описание, "framework", "YAxUnit"); + + Если ЗначениеЗаполнено(ОписаниеМодуля.epic) Тогда + ДобавитьМетку(Описание, "epic", ОписаниеМодуля.epic); + КонецЕсли; + + Если ЗначениеЗаполнено(ОписаниеМодуля.feature) Тогда + ДобавитьМетку(Описание, "feature", ОписаниеМодуля.feature); + КонецЕсли; + + Если ЗначениеЗаполнено(ОписаниеМодуля.story) Тогда + ДобавитьМетку(Описание, "story", ОписаниеМодуля.story); + КонецЕсли; + + ДобавитьМетку(Описание, "suite", ИмяНабора); + Если Модуль.НаборыТестов.Количество() > 1 ИЛИ Модуль.МетаданныеМодуля.Имя <> Набор.Представление Тогда + ДобавитьМетку(Описание, "subSuite", ИмяВложенногоНабора); + КонецЕсли; + + ДобавитьМетку(Описание, "tag", РезультатТеста.Режим); + + Для Каждого Тег Из РезультатТеста.Теги Цикл + ДобавитьМетку(Описание, "tag", Тег); + КонецЦикла; + + Если ЗначениеЗаполнено(РезультатТеста.Параметры) Тогда + Для Каждого Параметр Из РезультатТеста.Параметры Цикл + Описание.parameters.Добавить(Новый Структура("name, value", "П" + Описание.parameters.Количество(), Строка(Параметр))); + ПолныйИдентификаторТеста = ПолныйИдентификаторТеста + Строка(Параметр); + КонецЦикла; + КонецЕсли; + + Описание.historyId = ЮТОбщий.ХешMD5(ПолныйИдентификаторТеста); + + Для Каждого ОписаниеОшибки Из РезультатТеста.Ошибки Цикл + + Описание.statusDetails.message = ЮТСтроки.ДобавитьСтроку(Описание.statusDetails.message, ОписаниеОшибки.Сообщение, Символы.ПС); + Описание.statusDetails.trace = ЮТСтроки.ДобавитьСтроку(Описание.statusDetails.trace, ОписаниеОшибки.Стек, Символы.ПС); + + КонецЦикла; + + Если РезультатТеста.Ошибки.Количество() = 0 И РезультатТеста.Статус <> Статусы.Успешно Тогда + + Если РезультатТеста.Статус = Статусы.Ожидание Тогда + Описание.statusDetails.message = "Тест не был вызван"; + Иначе + Описание.statusDetails.message = "Тест не успешен, но нет сообщений об ошибках" + КонецЕсли; + + КонецЕсли; + + Возврат Описание; + +КонецФункции + +Функция НовыйОписаниеТеста() + + Описание = Новый Структура; + Описание.Вставить("uuid", ЮТТестовыеДанные.УникальнаяСтрока()); + Описание.Вставить("historyId", ""); + Описание.Вставить("testCaseId", ""); + Описание.Вставить("fullName", ""); + Описание.Вставить("name", ""); + Описание.Вставить("parameters", Новый Массив()); + Описание.Вставить("links", Новый Массив()); + Описание.Вставить("labels", Новый Массив()); + Описание.Вставить("status", ""); + Описание.Вставить("statusDetails", НовыйОписаниеСтатуса()); + Описание.Вставить("start", 0); + Описание.Вставить("stop", 0); + Описание.Вставить("steps", Новый Массив()); + + Возврат Описание; + +КонецФункции + +Функция НовыйОписаниеСтатуса() + + Описание = Новый Структура(); + Описание.Вставить("message"); + Описание.Вставить("trace"); + + Возврат Описание; + +КонецФункции + +Функция СтатусОтчета(Статус, Статусы) + + Если Статус = Статусы.Успешно Тогда + СтатусОтчета = "passed"; + ИначеЕсли Статус = Статусы.Ошибка Тогда + СтатусОтчета = "failed"; + ИначеЕсли Статус = Статусы.Пропущен Тогда + СтатусОтчета = "skipped"; + Иначе + СтатусОтчета = "broken"; + КонецЕсли; + + Возврат СтатусОтчета; + +КонецФункции + +Процедура ДобавитьМетку(ОписаниеТеста, ИмяМетки, Значение) + ОписаниеТеста.labels.Добавить(Новый Структура("name, value", ИмяМетки, Значение)); +КонецПроцедуры + +Функция ИмяМодуляПоСхеме(ИмяМодуля) + + Части = СтрРазделить(ИмяМодуля, "_"); + Описание = Новый Структура("epic, feature, story"); + Если Части.Количество() <> 2 И Части.Количество() <> 3 Тогда + Описание.epic = ИмяМодуля; + Возврат Описание; + КонецЕсли; + + Эпик = ТипОбъектаПоПрефиксу(Части[0]); + + Описание.epic = Эпик; + Описание.feature = Части[1]; + + Если Части.Количество() = 3 Тогда + Описание.story = ТипМодуляПоСуфииксу(Части[2]); + КонецЕсли; + + Возврат Описание; + +КонецФункции + +Функция ТипОбъектаПоПрефиксу(Префикс) + + ТипОбъекта = Неопределено; + + Если Префикс = "ОМ" Тогда ТипОбъекта = "Общий модуль"; + ИначеЕсли Префикс = "РБ" Тогда ТипОбъекта = "Регистр бухгалтерии"; + ИначеЕсли Префикс = "РН" Тогда ТипОбъекта = "Регистр накопления"; + ИначеЕсли Префикс = "РР" Тогда ТипОбъекта = "Регистр расчета"; + ИначеЕсли Префикс = "РС" Тогда ТипОбъекта = "Регистр сведений"; + ИначеЕсли Префикс = "БП" Тогда ТипОбъекта = "Бизнес процесс"; + ИначеЕсли Префикс = "Спр" Тогда ТипОбъекта = "Справочник"; + ИначеЕсли Префикс = "ПС" Тогда ТипОбъекта = "План счетов"; + ИначеЕсли Префикс = "ПВР" Тогда ТипОбъекта = "План видов расчета"; + ИначеЕсли Префикс = "ПВХ" Тогда ТипОбъекта = "План видов характеристик"; + ИначеЕсли Префикс = "Док" Тогда ТипОбъекта = "Документ"; + ИначеЕсли Префикс = "Пер" Тогда ТипОбъекта = "Перечисление"; + ИначеЕсли Префикс = "ПО" Тогда ТипОбъекта = "План обмена"; + ИначеЕсли Префикс = "Зад" Тогда ТипОбъекта = "Задача"; + ИначеЕсли Префикс = "Обр" Тогда ТипОбъекта = "Обработка"; + ИначеЕсли Префикс = "Отч" Тогда ТипОбъекта = "Отчет"; + Иначе ТипОбъекта = Префикс; + КонецЕсли; + + Возврат ТипОбъекта; +КонецФункции + +Функция ТипМодуляПоСуфииксу(Суффикс) + + ТипМодуля = Неопределено; + + Если Суффикс = "МО" Тогда ТипМодуля = "Модуль объекта"; + ИначеЕсли Суффикс = "ММ" Тогда ТипМодуля = "Модуль менеджера"; + ИначеЕсли Суффикс = "НЗ" Тогда ТипМодуля = "Модуль набора записей"; + Иначе ТипМодуля = Суффикс; + КонецЕсли; + + Возврат ТипМодуля; + +КонецФункции +#КонецЕсли + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТОтчетJSONСлужебный.xml b/src/cfe/YAXUnit/CommonModules/ЮТОтчетJSONСлужебный.xml new file mode 100644 index 0000000..90d1d4e --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТОтчетJSONСлужебный.xml @@ -0,0 +1,23 @@ + + + + + ЮТОтчетJSONСлужебный + + + ru + Отчет JSON + + + + false + true + false + false + true + false + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТОтчетJSONСлужебный/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТОтчетJSONСлужебный/Ext/Module.bsl new file mode 100644 index 0000000..a2b48bd --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТОтчетJSONСлужебный/Ext/Module.bsl @@ -0,0 +1,59 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область СлужебныйПрограммныйИнтерфейс + +Функция ПараметрыГенерацииОтчета() Экспорт + + Параметры = ЮТФабрикаСлужебный.ПараметрыГенератораОтчета(); + + ОписаниеФормата = ЮТФабрикаСлужебный.ОписаниеФорматаОтчета("dumpjson", "Дамп результата тестирования в json"); + ОписаниеФормата.ИмяФайлаПоУмолчанию = "report.json"; + ОписаниеФормата.ФильтрВыбораФайла = "Дамп результата тестирования (*.json)|*.json"; + Параметры.Форматы.Вставить(ОписаниеФормата.Идентификатор, ОписаниеФормата); + + Возврат Параметры; + +КонецФункции + +// Формирует отчет в формате JSON +// +// Параметры: +// РезультатВыполнения - Массив из см. ЮТФабрикаСлужебный.ОписаниеИсполняемогоТестовогоМодуля +// Формат - см. ЮТФабрикаСлужебный.ОписаниеФорматаОтчета +// Возвращаемое значение: +// ДвоичныеДанные - Данные отчета +Функция ДанныеОтчета(РезультатВыполнения, Формат) Экспорт + +#Если ВебКлиент Тогда + ВызватьИсключение "Формирование отчета в формате JSON не поддерживается в web-клиенте"; +#Иначе + Поток = Новый ПотокВПамяти(); + Запись = Новый ЗаписьJSON(); + Запись.ОткрытьПоток(Поток, "UTF-8", Ложь); + + ЗаписатьJSON(Запись, РезультатВыполнения); + + Запись.Закрыть(); + + Возврат Поток.ЗакрытьИПолучитьДвоичныеДанные(); +#КонецЕсли + +КонецФункции + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТОтчетJUnitСлужебный.xml b/src/cfe/YAXUnit/CommonModules/ЮТОтчетJUnitСлужебный.xml new file mode 100644 index 0000000..04da7d8 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТОтчетJUnitСлужебный.xml @@ -0,0 +1,23 @@ + + + + + ЮТОтчетJUnitСлужебный + + + ru + Отчет jUnit + + + + false + false + true + false + true + true + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТОтчетJUnitСлужебный/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТОтчетJUnitСлужебный/Ext/Module.bsl new file mode 100644 index 0000000..9259ebc --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТОтчетJUnitСлужебный/Ext/Module.bsl @@ -0,0 +1,344 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область СлужебныйПрограммныйИнтерфейс + +Функция ПараметрыГенерацииОтчета() Экспорт + + Параметры = ЮТФабрикаСлужебный.ПараметрыГенератораОтчета(); + + ОписаниеФормата = ЮТФабрикаСлужебный.ОписаниеФорматаОтчета("jUnit", "JUnit"); + ОписаниеФормата.ИмяФайлаПоУмолчанию = "junit.xml"; + ОписаниеФормата.ФильтрВыбораФайла = "jUnit(*.xml)|*.xml"; + Параметры.Форматы.Вставить(ОписаниеФормата.Идентификатор, ОписаниеФормата); + + Возврат Параметры; + +КонецФункции + +// Формирует отчет в формате jUnit +// +// Параметры: +// РезультатВыполнения - Массив из см. ЮТФабрикаСлужебный.ОписаниеИсполняемогоТестовогоМодуля +// Формат - см. ЮТФабрикаСлужебный.ОписаниеФорматаОтчета +// +// Возвращаемое значение: +// ДвоичныеДанные - Данные отчета +Функция ДанныеОтчета(Знач РезультатВыполнения, Формат) Экспорт + + Возврат СформироватьОтчетОТестировании(РезультатВыполнения); + +КонецФункции + +#КонецОбласти + +#Область СлужебныеПроцедурыИФункции + +// СформироватьОтчетОТестировании +// Формирует отчет (xml-файл) и возвращает его в виде двоичных данных +// +// Параметры: +// РезультатТестирования - Массив из см. ЮТФабрикаСлужебный.ОписаниеИсполняемогоТестовогоМодуля +// Возвращаемое значение: +// ДвоичныеДанные - полученный отчет +Функция СформироватьОтчетОТестировании(РезультатТестирования) + + Поток = Новый ПотокВПамяти(); + ЗаписьXML = Новый ЗаписьXML; + + ЗаписьXML.ОткрытьПоток(Поток, "UTF-8", Ложь); + ЗаписьXML.ЗаписатьОбъявлениеXML(); + ЗаписьXML.ЗаписатьНачалоЭлемента("testsuites"); + + Номер = 0; + + Для Каждого Модуль Из РезультатТестирования Цикл + + Для Каждого Набор Из Модуль.НаборыТестов Цикл + + ЗаписатьНабор(ЗаписьXML, Набор, Номер); + Номер = Номер + 1; + + КонецЦикла; + + КонецЦикла; + + ЗаписатьСвойства(ЗаписьXML, Новый Структура("executor, reportDate", "BIA YAxUnit", ТекущаяДатаСеанса())); + + ЗаписьXML.ЗаписатьКонецЭлемента(); + ЗаписьXML.Закрыть(); + + Возврат Поток.ЗакрытьИПолучитьДвоичныеДанные(); + +КонецФункции + +// ЗаписатьРезультатТеста +// +// Параметры: +// ЗаписьXML - ЗаписьXML - Запись XML +// РезультатТеста - Структура - Результат теста +Процедура ЗаписатьТест(ЗаписьXML, РезультатТеста) + + Статусы = ЮТФабрика.СтатусыИсполненияТеста(); + + ЗаписьXML.ЗаписатьНачалоЭлемента("testcase"); + ЗаписьXML.ЗаписатьАтрибут("name", РезультатТеста.Имя); + ЗаписьXML.ЗаписатьАтрибут("classname", РезультатТеста.ПолноеИмяМетода); + ЗаписьXML.ЗаписатьАтрибут("time", XMLСтрока(ЮТОбщий.ПродолжительностьВСекундах(РезультатТеста.Длительность))); + ЗаписьXML.ЗаписатьАтрибут("context", РезультатТеста.Режим); + + Для Каждого ОписаниеОшибки Из РезультатТеста.Ошибки Цикл + + Статус = ЮТРегистрацияОшибокСлужебный.СтатусОшибки(ОписаниеОшибки.ТипОшибки); + + ИмяУзла = Неопределено; + ЗаписатьЗначения = Ложь; + ЗаписатьСтек = Ложь; + Если Статус = Статусы.Ошибка Тогда + ИмяУзла = "failure"; + ЗаписатьЗначения = Истина; + ЗаписатьСтек = Истина; + ИначеЕсли Статус = Статусы.Пропущен Тогда + ИмяУзла = "skipped"; + ЗаписатьСтек = Истина; + ИначеЕсли Статус = Статусы.Ожидание Тогда + ИмяУзла = "skipped"; + ЗаписатьСтек = Истина; + ИначеЕсли Статус <> Статусы.Успешно Тогда + ИмяУзла = "error"; + ЗаписатьСтек = Истина; + КонецЕсли; + + Сообщение = СообщениеОбОшибке(ОписаниеОшибки); + ЗаписьXML.ЗаписатьНачалоЭлемента(ИмяУзла); + ЗаписьXML.ЗаписатьАтрибут("message", Сообщение); + + Если ЗначениеЗаполнено(ОписаниеОшибки.ТипОшибки) Тогда + ЗаписьXML.ЗаписатьАтрибут("type", XMLСтрока(ОписаниеОшибки.ТипОшибки)); + КонецЕсли; + + Если ЗаписатьЗначения Тогда + Если ОписаниеОшибки.ОжидаемоеЗначение <> Неопределено Тогда + ЗаписьXML.ЗаписатьНачалоЭлемента("expected"); + ЗаписьXML.ЗаписатьТекст(ЗначениеВСтрокуjUnit(ОписаниеОшибки.ОжидаемоеЗначение)); + ЗаписьXML.ЗаписатьКонецЭлемента(); + КонецЕсли; + + Если ОписаниеОшибки.ПроверяемоеЗначение <> Неопределено Тогда + ЗаписьXML.ЗаписатьНачалоЭлемента("actual"); + ЗаписьXML.ЗаписатьТекст(ЗначениеВСтрокуjUnit(ОписаниеОшибки.ПроверяемоеЗначение)); + ЗаписьXML.ЗаписатьКонецЭлемента(); + КонецЕсли; + КонецЕсли; + + Если ЗаписатьСтек И ОписаниеОшибки.Стек <> Неопределено Тогда + ЗаписьXML.ЗаписатьТекст(ОписаниеОшибки.Стек); + КонецЕсли; + + ЗаписьXML.ЗаписатьКонецЭлемента(); + + КонецЦикла; + + Если РезультатТеста.Ошибки.Количество() = 0 И РезультатТеста.Статус <> Статусы.Успешно Тогда + + Если РезультатТеста.Статус = Статусы.Ожидание Тогда + + ЗаписьXML.ЗаписатьНачалоЭлемента("skipped"); + ЗаписьXML.ЗаписатьАтрибут("message", "Тест не был вызван"); + ЗаписьXML.ЗаписатьКонецЭлемента(); + + Иначе + + ЗаписьXML.ЗаписатьНачалоЭлемента("error"); + ЗаписьXML.ЗаписатьАтрибут("message", "Тест не успешен, но нет сообщений об ошибках"); + ЗаписьXML.ЗаписатьКонецЭлемента(); + + КонецЕсли; + + КонецЕсли; + + ЗаписьXML.ЗаписатьКонецЭлемента(); + +КонецПроцедуры + +Процедура ЗаписатьОшибку(ЗаписьXML, ОписаниеОшибки) + Сообщение = СообщениеОбОшибке(ОписаниеОшибки); + ЗаписьXML.ЗаписатьНачалоЭлемента("error"); + ЗаписьXML.ЗаписатьАтрибут("message", Сообщение); + + Если ЗначениеЗаполнено(ОписаниеОшибки.ТипОшибки) Тогда + ЗаписьXML.ЗаписатьАтрибут("type", XMLСтрока(ОписаниеОшибки.ТипОшибки)); + КонецЕсли; + + Если ЗначениеЗаполнено(ОписаниеОшибки.Стек) Тогда + ЗаписьXML.ЗаписатьТекст(ОписаниеОшибки.Стек); + КонецЕсли; + + ЗаписьXML.ЗаписатьКонецЭлемента(); +КонецПроцедуры + +Процедура ЗаписатьНабор(ЗаписьXML, Набор, Номер) + + КоличествоТестов = 0; + КоличествоПропущенных = 0; + КоличествоУпавших = 0; + КоличествоСломанных = 0; + + Статусы = ЮТФабрика.СтатусыИсполненияТеста(); + + Для Каждого РезультатТеста Из Набор.Тесты Цикл + + КоличествоТестов = КоличествоТестов + 1; + + Если РезультатТеста.Статус = Статусы.Ошибка Тогда + КоличествоУпавших = КоличествоУпавших + 1; + ИначеЕсли РезультатТеста.Статус = Статусы.Пропущен ИЛИ РезультатТеста.Статус = Статусы.Ожидание Тогда + КоличествоПропущенных = КоличествоПропущенных + 1; + ИначеЕсли РезультатТеста.Статус <> Статусы.Успешно Тогда + КоличествоСломанных = КоличествоСломанных + 1; + КонецЕсли; + + КонецЦикла; + + ЗаписьXML.ЗаписатьНачалоЭлемента("testsuite"); + ЗаписьXML.ЗаписатьАтрибут("id", XMLСтрока(Номер)); + ЗаписьXML.ЗаписатьАтрибут("name", СтрШаблон("%1 [%2]", Набор.Представление, Набор.Режим)); + ЗаписьXML.ЗаписатьАтрибут("tests", XMLСтрока(КоличествоТестов)); + ЗаписьXML.ЗаписатьАтрибут("errors", XMLСтрока(КоличествоСломанных)); + ЗаписьXML.ЗаписатьАтрибут("skipped", XMLСтрока(КоличествоПропущенных)); + ЗаписьXML.ЗаписатьАтрибут("failures", XMLСтрока(КоличествоУпавших)); + ЗаписьXML.ЗаписатьАтрибут("timestamp", XMLСтрока(ЮТОбщий.МестноеВремяПоВременнойМетке(Набор.ДатаСтарта))); + ЗаписьXML.ЗаписатьАтрибут("time", XMLСтрока(ЮТОбщий.ПродолжительностьВСекундах(Набор.Длительность))); + ЗаписьXML.ЗаписатьАтрибут("package", Набор.МетаданныеМодуля.Расширение); + ЗаписьXML.ЗаписатьАтрибут("context", Набор.Режим); + + Для Каждого ОписаниеОшибки Из Набор.Ошибки Цикл + ЗаписатьОшибку(ЗаписьXML, ОписаниеОшибки); + КонецЦикла; + + Для Каждого РезультатТеста Из Набор.Тесты Цикл + + ЗаписатьТест(ЗаписьXML, РезультатТеста); + + КонецЦикла; + + ЗаписатьСвойства(ЗаписьXML, Новый Структура("context", Набор.Режим)); + ЗаписьXML.ЗаписатьКонецЭлемента(); // testsuite + +КонецПроцедуры + +Функция ЗначениеВСтрокуjUnit(Знач Значение) + + ТипЗначения = ТипЗнч(Значение); + + Если ТипЗначения = Тип("Строка") Тогда + + Возврат XMLСтрока(Значение); + + ИначеЕсли ТипЗначения = Тип("Массив") Тогда + + Возврат ЗначениеВСтрокуМассивjUnit(Значение); + + ИначеЕсли ТипЗначения = Тип("Структура") Или ТипЗначения = Тип("Соответствие") Или ТипЗначения = Тип("СписокЗначений") Тогда + + Возврат ЗначениеВСтрокуПростаяКоллекцияjUnit(Значение); + + ИначеЕсли ТипЗначения = Тип("Тип") Или ТипЗначения = Тип("СтандартныйПериод") Тогда + + Возврат Строка(Значение); + + Иначе + + Попытка + + Возврат XMLСтрока(Значение); + + Исключение + + Возврат Строка(Значение); + + КонецПопытки; + + КонецЕсли; + +КонецФункции + +Функция ЗначениеВСтрокуМассивjUnit(Коллекция) + + Стр = ""; + + Для Ккк = 0 По Коллекция.Количество() - 1 Цикл + + Стр = Стр + ЗначениеВСтрокуjUnit(Коллекция[Ккк]); + + Если Ккк < Коллекция.Количество() - 1 Тогда + + Стр = Стр + Символы.ПС; + + КонецЕсли; + + КонецЦикла; + + Возврат Стр; + +КонецФункции + +Функция ЗначениеВСтрокуПростаяКоллекцияjUnit(Коллекция) + + Стр = "|"; + + Для Каждого Элем Из Коллекция Цикл + + Стр = " " + Стр + Элем.Значение + " |"; + + КонецЦикла; + + Возврат Стр; + +КонецФункции + +Функция СообщениеОбОшибке(ОписаниеОшибки) + + Если ТипЗнч(ОписаниеОшибки) = Тип("Структура") Тогда + Сообщение = ОписаниеОшибки.Сообщение; + ИначеЕсли ЗначениеЗаполнено(ОписаниеОшибки) Тогда + Сообщение = Строка(ОписаниеОшибки); + Иначе + Сообщение = Неопределено; + КонецЕсли; + + Возврат Сообщение; + +КонецФункции + +Процедура ЗаписатьСвойства(ЗаписьXML, Свойства) + + ЗаписьXML.ЗаписатьНачалоЭлемента("properties"); + + Для Каждого Свойство Из Свойства Цикл + ЗаписьXML.ЗаписатьНачалоЭлемента("property"); + ЗаписьXML.ЗаписатьАтрибут("name", Свойство.Ключ); + ЗаписьXML.ЗаписатьАтрибут("value", ЗначениеВСтрокуjUnit(Свойство.Значение)); + ЗаписьXML.ЗаписатьКонецЭлемента(); // property + КонецЦикла; + + ЗаписьXML.ЗаписатьКонецЭлемента(); // properties + +КонецПроцедуры + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТОтчетСлужебный.xml b/src/cfe/YAXUnit/CommonModules/ЮТОтчетСлужебный.xml new file mode 100644 index 0000000..5b93afa --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТОтчетСлужебный.xml @@ -0,0 +1,23 @@ + + + + + ЮТОтчетСлужебный + + + ru + Отчет + + + + false + true + false + false + true + false + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТОтчетСлужебный/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТОтчетСлужебный/Ext/Module.bsl new file mode 100644 index 0000000..48dae26 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТОтчетСлужебный/Ext/Module.bsl @@ -0,0 +1,169 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область СлужебныйПрограммныйИнтерфейс + +// СформироватьОтчет +// Формирует отчет о результатах тестирования по заданным параметрам +// Параметры: +// РезультатВыполнения - Массив из см. ЮТФабрикаСлужебный.ОписаниеИсполняемогоТестовогоМодуля +// ПараметрыЗапуска - Структура - Параметры запуска, см. ЮТФабрика.ПараметрыЗапуска +// Обработчик - ОписаниеОповещения +Процедура СформироватьОтчет(РезультатВыполнения, ПараметрыЗапуска, Обработчик) Экспорт + + Если НЕ ЗначениеЗаполнено(ПараметрыЗапуска.reportPath) Тогда + ЮТЛогирование.Ошибка("Не указан путь сохранения отчета"); + ЮТАсинхроннаяОбработкаСлужебныйКлиент.ВызватьОбработчик(Обработчик); + Возврат; + КонецЕсли; + + ПараметрыФормирования = МодульФормирования(ПараметрыЗапуска.reportFormat); + + Если ПараметрыФормирования = Неопределено Тогда + ЮТЛогирование.Ошибка(СтрШаблон("Отчет в формате `%1` не поддерживается", ПараметрыЗапуска.reportFormat)); + ЮТАсинхроннаяОбработкаСлужебныйКлиент.ВызватьОбработчик(Обработчик); + Возврат; + КонецЕсли; + + МодульОтчета = ПараметрыФормирования.Модуль; + Формат = ПараметрыФормирования.Формат; + ПараметрыФормирования = Новый Структура("РезультатВыполнения, ПараметрыЗапуска, Обработчик", РезультатВыполнения, ПараметрыЗапуска, Обработчик); + ПараметрыФормирования.Вставить("МодульОтчета", МодульОтчета); + ПараметрыФормирования.Вставить("Формат", Формат); + + ОбработчикПолученияИмениФайла = Новый ОписаниеОповещения("ПослеФормированияИмениФайла", ЭтотОбъект, ПараметрыФормирования); + ПодготовитьИмяФайлаОтчета(ПараметрыФормирования, ОбработчикПолученияИмениФайла); + +КонецПроцедуры + +// Поддерживаемые форматы отчетов. +// +// Возвращаемое значение: +// Структура - Поддерживаемые форматы отчетов +// + Ключ - Идентификатор формата +// + Значение - см. ЮТФабрикаСлужебный.ОписаниеФорматаОтчета +Функция ПоддерживаемыеФорматыОтчетов() Экспорт + + Модули = ЮТРасширенияСлужебный.ГенераторыОтчетов(); + Форматы = Новый Структура; + + Для Каждого Модуль Из Модули Цикл + + Параметры = Модуль.ПараметрыГенерацииОтчета(); + ЮТКоллекции.ДополнитьСтруктуру(Форматы, Параметры.Форматы); + + КонецЦикла; + + Возврат Форматы; + +КонецФункции + +#КонецОбласти + +#Область СлужебныеПроцедурыИФункции + +Процедура СформироватьОтчетВФормате(РезультатВыполнения, ГенераторОтчета, ИмяФайлаОтчета, Формат, Обработчик) + + Если Формат.СамостоятельнаяЗаписьОтчета Тогда + ГенераторОтчета.ЗаписатьОтчет(РезультатВыполнения, ИмяФайлаОтчета, Формат, Обработчик) + Иначе + ДанныеОтчета = ГенераторОтчета.ДанныеОтчета(РезультатВыполнения, Формат); + + Если ДанныеОтчета = Неопределено Тогда + ЮТЛогирование.Ошибка("Не удалось получить данные отчета"); + Иначе + ДанныеОтчета.Записать(ИмяФайлаОтчета); + КонецЕсли; + КонецЕсли; + + ЮТАсинхроннаяОбработкаСлужебныйКлиент.ВызватьОбработчик(Обработчик); + +КонецПроцедуры + +Процедура ПодготовитьИмяФайлаОтчета(ПараметрыФормирования, Обработчик) + + ПараметрыПроверки = Новый Структура("ПараметрыФормирования, Обработчик", ПараметрыФормирования, Обработчик); + + ОбработчикПроверки = Новый ОписаниеОповещения("ПослеПроверкиСуществования", ЭтотОбъект, ПараметрыПроверки); + ЮТФайлы.Существует(ПараметрыФормирования.ПараметрыЗапуска.reportPath, ОбработчикПроверки); + +КонецПроцедуры + +Функция МодульФормирования(Формат) + + Модули = ЮТРасширенияСлужебный.ГенераторыОтчетов(); + + Для Каждого Модуль Из Модули Цикл + + Параметры = Модуль.ПараметрыГенерацииОтчета(); + Если Параметры.Форматы.Свойство(Формат) Тогда + Возврат Новый Структура("Модуль, Формат", Модуль, Параметры.Форматы[Формат]); + КонецЕсли; + + КонецЦикла; + + Возврат Неопределено; + +КонецФункции + +Процедура ПослеПроверкиСуществования(Существует, Параметры) Экспорт + + ПутьКОтчету = Параметры.ПараметрыФормирования.ПараметрыЗапуска.reportPath; + Если Существует Тогда + ОбработчикПроверки = Новый ОписаниеОповещения("ПослеПроверкиКаталога", ЭтотОбъект, Параметры); + ЮТФайлы.ЭтоКаталог(ПутьКОтчету, ОбработчикПроверки); + Возврат + КонецЕсли; + + Формат = Параметры.ПараметрыФормирования.Формат; + Если Формат.ЗаписьВКаталог Тогда + НачатьСозданиеКаталога(Новый ОписаниеОповещения("ПослеСозданияКаталогаОтчета", ЭтотОбъект, Параметры), ПутьКОтчету); + Иначе + ПослеПроверкиКаталога(Ложь, Параметры); + КонецЕсли; + +КонецПроцедуры + +Процедура ПослеСозданияКаталогаОтчета(ИмяКаталога, Параметры) Экспорт + + ПослеПроверкиКаталога(Истина, Параметры); + +КонецПроцедуры + +Процедура ПослеПроверкиКаталога(ЭтоКаталог, Параметры) Экспорт + + ПутьКОтчету = Параметры.ПараметрыФормирования.ПараметрыЗапуска.reportPath; + Формат = Параметры.ПараметрыФормирования.Формат; + + Если НЕ Формат.ЗаписьВКаталог И ЭтоКаталог Тогда + ИмяФайла = ЮТФайлы.ОбъединитьПути(ПутьКОтчету, Формат.ИмяФайлаПоУмолчанию); + Иначе + ИмяФайла = ПутьКОтчету; + КонецЕсли; + + ЮТАсинхроннаяОбработкаСлужебныйКлиент.ВызватьОбработчик(Параметры.Обработчик, ИмяФайла); + +КонецПроцедуры + +Процедура ПослеФормированияИмениФайла(ИмяФайлаОтчета, Параметры) Экспорт + + СформироватьОтчетВФормате(Параметры.РезультатВыполнения, Параметры.МодульОтчета, ИмяФайлаОтчета, Параметры.Формат, Параметры.Обработчик); + +КонецПроцедуры + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТПараметрыЗапускаСлужебный.xml b/src/cfe/YAXUnit/CommonModules/ЮТПараметрыЗапускаСлужебный.xml new file mode 100644 index 0000000..aa762a3 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТПараметрыЗапускаСлужебный.xml @@ -0,0 +1,23 @@ + + + + + ЮТПараметрыЗапускаСлужебный + + + ru + Параметры + + + Используется для обработки и дополнения параметров запуска тестов + false + true + false + false + true + false + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТПараметрыЗапускаСлужебный/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТПараметрыЗапускаСлужебный/Ext/Module.bsl new file mode 100644 index 0000000..5eb5ae0 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТПараметрыЗапускаСлужебный/Ext/Module.bsl @@ -0,0 +1,175 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область СлужебныйПрограммныйИнтерфейс + +// ПараметрыЗапуска +// Возвращает загруженные параметры запуска тестирования +// Параметры: +// ПараметрыЗапускаСтрокой - Строка - Параметры запуска приложения +// Обработчик - ОписаниеОповещения +// +// Возвращаемое значение: +// см. ЮТФабрика.ПараметрыЗапуска +Функция ПараметрыЗапуска(Знач ПараметрыЗапускаСтрокой, Обработчик) Экспорт + + Попытка + + Параметры = ПрочитатьПараметрыЗапуска(ПараметрыЗапускаСтрокой, Обработчик); + + Исключение + + ЮТРегистрацияОшибокСлужебный.ЗарегистрироватьОшибкуИнициализацииДвижка(ИнформацияОбОшибке(), "Ошибка чтения параметров запуска"); + Параметры = ЮТФабрика.ПараметрыЗапуска(); + + КонецПопытки; + + Возврат Параметры; + +КонецФункции + +Функция КлючЗапуска() Экспорт + + Возврат "RunUnitTests"; + +КонецФункции + +#КонецОбласти + +#Область СлужебныеПроцедурыИФункции + +// ПрочитатьПараметрыЗапуска +// Читает параметры из строки запуска +// Параметры: +// ПараметрыЗапускаСтрокой - Строка - Строка с параметрами запуска. +// Содержит ключ запуска и строку с конфигурационным файлом. +// Формат строки "RunUnitTests=/путь/к/конфигурационному/файлу", +// где ключ указывается обязательно, а путь - по желанию +// Обработчик - ОписаниеОповещения +// +// Возвращаемое значение: +// см. ЮТФабрика.ПараметрыЗапуска +Функция ПрочитатьПараметрыЗапуска(Знач ПараметрыЗапускаСтрокой, Обработчик) + + Параметры = ЮТФабрика.ПараметрыЗапуска(); + + Если Не ЗначениеЗаполнено(ПараметрыЗапускаСтрокой) Тогда + ЮТАсинхроннаяОбработкаСлужебныйКлиент.ВызватьОбработчик(Обработчик, Параметры); + Возврат Параметры; + КонецЕсли; + + ПарыКлючЗначение = ЮТСтроки.РазделитьСтроку(ПараметрыЗапускаСтрокой, ";"); + + ПараметрыЗапуска = Новый Структура; + + Для Каждого Пара Из ПарыКлючЗначение Цикл + + Если ПустаяСтрока(Пара) Тогда + Продолжить; + КонецЕсли; + + КлючЗначение = ЮТСтроки.РазделитьСтроку(Пара, "="); + + Если КлючЗначение.Количество() = 1 Тогда + ПараметрыЗапуска.Вставить(КлючЗначение[0], Истина); + Иначе + ПараметрыЗапуска.Вставить(КлючЗначение[0], КлючЗначение[1]); + КонецЕсли; + + КонецЦикла; + + ЗначениеКлючаЗапуска = ЮТКоллекции.ЗначениеСтруктуры(ПараметрыЗапуска, КлючЗапуска(), Ложь); + + Если ТипЗнч(ЗначениеКлючаЗапуска) = Тип("Булево") Тогда + + Параметры.ВыполнятьМодульноеТестирование = ЗначениеКлючаЗапуска; + Параметры.showReport = Истина; + Параметры.closeAfterTests = Ложь; + + ИначеЕсли ТипЗнч(ЗначениеКлючаЗапуска) = Тип("Строка") Тогда + + Параметры.ВыполнятьМодульноеТестирование = Истина; + КонфигурационныйФайл = ЗначениеКлючаЗапуска; + + КонецЕсли; + + Если ЗначениеЗаполнено(КонфигурационныйФайл) Тогда + + ПараметрыИзФайла = ПрочитатьКонфигурационныйФайл(КонфигурационныйФайл); + ДополнитьПараметрыПрочитанными(Параметры, ПараметрыИзФайла); + + КонецЕсли; + + ЮТАсинхроннаяОбработкаСлужебныйКлиент.ВызватьОбработчик(Обработчик, Параметры); + + Возврат Параметры; + +КонецФункции + +Функция ПрочитатьКонфигурационныйФайл(ПутьКФайлу) + +#Если НЕ ВебКлиент Тогда + + Если ЮТОбщий.УстановленБезопасныйРежим() Тогда + ВызватьИсключение "Расширение подключено в безопасном режиме. Чтение конфигурационного файла недоступно"; + КонецЕсли; + + ДанныеФайла = Неопределено; + + Попытка + + Текст = ЮТОбщий.ДанныеТекстовогоФайла(ПутьКФайлу); + + Если ЗначениеЗаполнено(Текст) Тогда + ДанныеФайла = ЮТОбщий.ЗначениеИзJSON(Текст); + КонецЕсли; + + Исключение + + ВызватьИсключение; + + КонецПопытки; + + Возврат ДанныеФайла; + +#Иначе + // будут использованы параметры по умолчанию + Возврат Новый Структура; +#КонецЕсли + +КонецФункции + +Процедура ДополнитьПараметрыПрочитанными(Параметры, ДанныеДополнения) + + Для Каждого Параметр Из ДанныеДополнения Цикл + + Если НЕ Параметры.Свойство(Параметр.Ключ) Тогда + Продолжить; + КонецЕсли; + + Если ТипЗнч(Параметры[Параметр.Ключ]) = ТипЗнч(Параметр.Значение) Тогда + + Параметры[Параметр.Ключ] = Параметр.Значение; + + КонецЕсли; + + КонецЦикла; + +КонецПроцедуры + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТПодражатель.xml b/src/cfe/YAXUnit/CommonModules/ЮТПодражатель.xml new file mode 100644 index 0000000..04f1f0d --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТПодражатель.xml @@ -0,0 +1,23 @@ + + + + + ЮТПодражатель + + + ru + Подражатель + + + + false + true + true + false + true + false + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТПодражатель/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТПодражатель/Ext/Module.bsl new file mode 100644 index 0000000..0a0ae76 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТПодражатель/Ext/Module.bsl @@ -0,0 +1,65 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2023 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область ПрограммныйИнтерфейс + +// Локализация. +// +// Возвращаемое значение: +// Строка - Возвращает текущую установленную локализацию +Функция Локализация() Экспорт + Возврат ЮТПодражательСлужебный.Контекст().Локализация; +КонецФункции + +// Устанавливает локализацию подражателя +// В дальнейшем используется для получения списка словарей с указанной локализацией +// Параметры: +// КодЯзыка - Строка - Код языка +Процедура УстановитьЛокализацию(КодЯзыка) Экспорт + ЮТПодражательСлужебный.Контекст().Локализация = КодЯзыка; +КонецПроцедуры + +#Область Реализации + +// Подражатель для людей +// +// Возвращаемое значение: +// CommonModule.ЮТПодражатель_Люди - Люди +Функция Люди() Экспорт + Возврат ЮТПодражатель_Люди; +КонецФункции + +// Подражатель для компаний +// +// Возвращаемое значение: +// CommonModule.ЮТПодражатель_Компании - Компании +Функция Компании() Экспорт + Возврат ЮТПодражатель_Компании; +КонецФункции + +// Подражатель для банков +// +// Возвращаемое значение: +// CommonModule.ЮТПодражатель_Банки - Банки +Функция Банки() Экспорт + Возврат ЮТПодражатель_Банки; +КонецФункции + +#КонецОбласти + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТПодражатель_Банки.xml b/src/cfe/YAXUnit/CommonModules/ЮТПодражатель_Банки.xml new file mode 100644 index 0000000..0161416 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТПодражатель_Банки.xml @@ -0,0 +1,23 @@ + + + + + ЮТПодражатель_Банки + + + ru + Подражатель реализация люди клиент сервер + + + + false + true + true + false + true + false + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТПодражатель_Банки/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТПодражатель_Банки/Ext/Module.bsl new file mode 100644 index 0000000..f0df91b --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТПодражатель_Банки/Ext/Module.bsl @@ -0,0 +1,85 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область ПрограммныйИнтерфейс + +// Возвращает случайный номер банковского счета, по умолчанию +// Подробности алгоритма можно прочитать по ссылке +// http://keysystems.ru/files/fo/arm_budjet/show_docum/BKS/onlinehelphtm/ro_kr_algor_klyuch_rs.htm +// Параметры: +// БИК - Строка - БИК банка +// КодВалюты - Строка - Код валюты +// ЮрЛицо - Булево - Генерация счета юрлица, иначе физ лица +// +// Возвращаемое значение: +// Строка - Номер счета +Функция НомерСчета(БИК, КодВалюты = "810", ЮрЛицо = Истина) Экспорт + + Если СтрДлина(КодВалюты) <> 3 Тогда + ВызватьИсключение ЮТИсключения.НекорректныеПараметрыМетода("НомерСчета", "Длина кода валюты должна быть равна 3"); + КонецЕсли; + + БалансовыйСчет = ?(ЮрЛицо, "40702", "40802"); + НомерСчетаВБанке = ЮТТестовыеДанные.СлучайнаяСтрока(11, , "0123456789"); + + ЧислоДляРасчетаКонтрольнойСуммы = Прав(БИК, 3) + БалансовыйСчет + КодВалюты + "0" + НомерСчетаВБанке; + Весы = ВесовыеКоэффициентаДляРасчетаКонтрольнойСуммыСчета(); + + КонтрольнаяСумма = 0; + Для Индекс = 0 По 22 Цикл + КонтрольнаяСумма = + КонтрольнаяСумма + + Число(Сред(ЧислоДляРасчетаКонтрольнойСуммы, Индекс + 1, 1)) * Число(Весы.Получить(Индекс)) + ; + КонецЦикла; + + КонтрольноеЧисло = ((КонтрольнаяСумма % 10) * 3) % 10; + + Возврат СтрШаблон( + "%1%2%3%4", + БалансовыйСчет, + КодВалюты, + КонтрольноеЧисло, + НомерСчетаВБанке + ); + +КонецФункции + +// Формирует случайный валидный БИК банка +// +// Возвращаемое значение: +// Строка - БИК +Функция БИК() Экспорт + Возврат СтрШаблон( + "%1%2%3%4", + "04", // код страны + ЮТТестовыеДанные.СлучайнаяСтрока(2, , "0123456789"), // ОКАТО код территории + ЮТТестовыеДанные.СлучайнаяСтрока(2, , "0123456789"), // код подразделение расчетной сети ЦБ + Формат(ЮТТестовыеДанные.СлучайноеЧисло(50, 999), "ЧЦ=3; ЧВН=;") // номер кредитной организации + ); +КонецФункции + +#КонецОбласти + +#Область СлужебныеПроцедурыИФункции + +Функция ВесовыеКоэффициентаДляРасчетаКонтрольнойСуммыСчета() + Возврат СтрРазделить("7,1,3,7,1,3,7,1,3,7,1,3,7,1,3,7,1,3,7,1,3,7,1", ","); +КонецФункции + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТПодражатель_Компании.xml b/src/cfe/YAXUnit/CommonModules/ЮТПодражатель_Компании.xml new file mode 100644 index 0000000..17ed7f2 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТПодражатель_Компании.xml @@ -0,0 +1,23 @@ + + + + + ЮТПодражатель_Компании + + + ru + Подражатель реализация люди клиент сервер + + + + false + true + true + false + true + false + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТПодражатель_Компании/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТПодражатель_Компании/Ext/Module.bsl new file mode 100644 index 0000000..43cd0d4 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТПодражатель_Компании/Ext/Module.bsl @@ -0,0 +1,150 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2023 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область ПрограммныйИнтерфейс + +// Возвращает случайное имя компании +// +// Возвращаемое значение: +// Строка +Функция Наименование() Экспорт + + СловарьИмен = СловарьИменаКомпаний(); + СловарьПрефиксов = СловарьПрефиксыИменКомпаний(); + + Возврат СтрШаблон( + "%1 %2", + ЮТПодражательСлужебный.СлучайноеЗначениеИзСловаря(СловарьПрефиксов), + ЮТПодражательСлужебный.СлучайноеЗначениеИзСловаря(СловарьИмен) + ); + +КонецФункции + +// Формирует случайный валидный ИНН РФ. +// +// Параметры: +// КодРегиона - Строка - Код региона это первые две цифры кода ИНН. Список действующих кодов регионов +// можно подсмотреть: https://www.nalog.gov.ru/html/docs/kods_regions.doc . Если код региона задан +// как "00" то будет сформирован случайный код региона. По умолчанию "00" (случайный код региона) +// ЭтоИННФизическогоЛица - Булево - Если Истина, то это ИНН физического лица, иначе ИНН юридического +// лица. По умолчанию Ложь (ИНН юридического лица) +// +// Возвращаемое значение: +// Строка - Случайный ИНН, например 3444140904 +Функция ИНН(КодРегиона = "00", ЭтоИННФизическогоЛица = Ложь) Экспорт + + СлучайныйИНН = ""; + + Если ЭтоИННФизическогоЛица Тогда + ИННМассив = Новый Массив(12); + ВесовыеКоэффициенты1 = СтрРазделить("7, 2, 4, 10, 3, 5, 9, 4, 6, 8", ","); + ВесовыеКоэффициенты2 = СтрРазделить("3, 7, 2, 4, 10, 3, 5, 9, 4, 6, 8", ","); + Иначе + ИННМассив = Новый Массив(10); + ВесовыеКоэффициенты1 = СтрРазделить("2, 4, 10, 3, 5, 9, 4, 6, 8", ","); + ВесовыеКоэффициенты2 = Новый Массив; + КонецЕсли; + + Если КодРегиона = "00" Или СтрДлина(КодРегиона) <> 2 Тогда + ИННМассив.Установить(0, ЮТТестовыеДанные.СлучайноеЧисло(0, 9, 0)); + ИННМассив.Установить(1, ЮТТестовыеДанные.СлучайноеЧисло(0, 9, 0)); + Иначе + ИННМассив.Установить(0, Число(Сред(КодРегиона, 1, 1))); + ИННМассив.Установить(1, Число(Сред(КодРегиона, 2, 1))); + КонецЕсли; + + Для Индекс = 2 По ИННМассив.ВГраница() Цикл + ИННМассив.Установить(Индекс, ЮТТестовыеДанные.СлучайноеЧисло(0, 9, 0)); + КонецЦикла; + + Сумма1 = 0; + Для Индекс = 0 По ВесовыеКоэффициенты1.ВГраница() Цикл + Элемент = ИННМассив.Получить(Индекс) * Число(ВесовыеКоэффициенты1.Получить(Индекс)); + Сумма1 = Сумма1 + Элемент; + КонецЦикла; + ИННМассив.Установить(ВесовыеКоэффициенты1.Количество(), Сумма1 % 11 % 10); + + Если ВесовыеКоэффициенты2.Количество() <> 0 Тогда + Сумма2 = 0; + Для Индекс = 0 По ВесовыеКоэффициенты2.ВГраница() Цикл + Элемент = ИННМассив.Получить(Индекс) * Число(ВесовыеКоэффициенты2.Получить(Индекс)); + Сумма2 = Сумма2 + Элемент; + КонецЦикла; + ИННМассив.Установить(ВесовыеКоэффициенты2.Количество(), Сумма1 % 11 % 10); + КонецЕсли; + + СлучайныйИНН = СтрСоединить(ИННМассив); + + Возврат СлучайныйИНН; +КонецФункции + +// Формирует случайный валидный КПП РФ +// +// Параметры: +// КодНалоговогоОргана - Строка - Код налогового органа, первые четыре цифры КПП. +// Причина - Число - Причина постановки. Поддерживаются следующие варианты +// # 2 - код причины "43" постановка на учет филиала российской организации +// # любая другая цифра - код причины "01" постановка на учет российской организации +// по месту ее нахождения +// +// Возвращаемое значение: +// Строка - Случайный КПП, например 344401001 +Функция КПП(КодНалоговогоОргана = "0000", Причина = 1) Экспорт + + СлучайныйКПП = ""; + + Если ТипЗнч(Причина) = Тип("Число") И Причина = 2 Тогда + Код2 = "43"; + Иначе + Код2 = "01"; + КонецЕсли; + + Если ТипЗнч(КодНалоговогоОргана) = Тип("Строка") И СтрДлина(КодНалоговогоОргана) = 4 Тогда + Код1 = КодНалоговогоОргана; + Иначе + МассивКод1 = Новый Массив(4); + Для Индекс = 0 По МассивКод1.ВГраница() Цикл + МассивКод1.Установить(Индекс, ЮТТестовыеДанные.СлучайноеЧисло(0, 9, 0)); + КонецЦикла; + Код1 = СтрСоединить(МассивКод1); + КонецЕсли; + + Код3 = "00" + Строка(ЮТТестовыеДанные.СлучайноеЧисло(0, 9, 0)); + + СлучайныйКПП = СтрШаблон("%1%2%3", Код1, Код2, Код3); + + Возврат СлучайныйКПП; +КонецФункции + +#КонецОбласти + +#Область СлужебныеПроцедурыИФункции + +Функция ИмяРеализации() + Возврат "Компании"; +КонецФункции + +Функция СловарьИменаКомпаний() + Возврат ЮТПодражательСлужебный.Словарь(ИмяРеализации(), "Наименования"); +КонецФункции + +Функция СловарьПрефиксыИменКомпаний() + Возврат ЮТПодражательСлужебный.Словарь(ИмяРеализации(), "ПрефиксыНаименований"); +КонецФункции + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТПодражатель_Люди.xml b/src/cfe/YAXUnit/CommonModules/ЮТПодражатель_Люди.xml new file mode 100644 index 0000000..f621f18 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТПодражатель_Люди.xml @@ -0,0 +1,23 @@ + + + + + ЮТПодражатель_Люди + + + ru + Подражатель реализация люди клиент сервер + + + + false + true + true + false + true + false + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТПодражатель_Люди/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТПодражатель_Люди/Ext/Module.bsl new file mode 100644 index 0000000..716b13c --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТПодражатель_Люди/Ext/Module.bsl @@ -0,0 +1,204 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область ПрограммныйИнтерфейс + +// Возвращает случайное имя +// +// Параметры: +// Пол - Строка - см. ЮТПодражатель_Люди.ПолЧеловека +// +// Возвращаемое значение: +// Строка +Функция Имя(Пол = Неопределено) Экспорт + + ПолЧеловека = ОпределитьПолЧеловекаИзПараметра(Пол); + + Если ПолЧеловека = ПолЧеловека().Мужской Тогда + Словарь = СловарьМужскиеИмена(); + ИначеЕсли ПолЧеловека = ПолЧеловека().Женский Тогда + Словарь = СловарьЖенскиеИмена(); + КонецЕсли; + + Возврат ЮТПодражательСлужебный.СлучайноеЗначениеИзСловаря(Словарь); + +КонецФункции + +// Возвращает случайную фамилию +// +// Параметры: +// Пол - Строка - см. ЮТПодражатель_Люди.ПолЧеловека +// +// Возвращаемое значение: +// Строка +Функция Фамилия(Пол = Неопределено) Экспорт + + ПолЧеловека = ОпределитьПолЧеловекаИзПараметра(Пол); + + Если ПолЧеловека = ПолЧеловека().Мужской Тогда + Словарь = СловарьМужскиеФамилии(); + ИначеЕсли ПолЧеловека = ПолЧеловека().Женский Тогда + Словарь = СловарьЖенскиеФамилии(); + КонецЕсли; + + Возврат ЮТПодражательСлужебный.СлучайноеЗначениеИзСловаря(Словарь); + +КонецФункции + +// Возвращает случайное отчество +// +// Параметры: +// Пол - Строка - см. ЮТПодражатель_Люди.ПолЧеловека +// +// Возвращаемое значение: +// Строка +Функция Отчество(Пол = Неопределено) Экспорт + + ПолЧеловека = ОпределитьПолЧеловекаИзПараметра(Пол); + + Если ПолЧеловека = ПолЧеловека().Мужской Тогда + Словарь = СловарьМужскиеОтчества(); + ИначеЕсли ПолЧеловека = ПолЧеловека().Женский Тогда + Словарь = СловарьЖенскиеОтчества(); + КонецЕсли; + + Возврат ЮТПодражательСлужебный.СлучайноеЗначениеИзСловаря(Словарь); + +КонецФункции + +// Возвращает случайное отчество +// +// Параметры: +// Пол - Строка - см. ЮТПодражатель_Люди.ПолЧеловека +// +// Возвращаемое значение: +// Строка +Функция ФИО(Пол = Неопределено) Экспорт + + ПолЧеловека = ОпределитьПолЧеловекаИзПараметра(Пол); + + Возврат СтрШаблон( + "%1 %2 %3", + Фамилия(ПолЧеловека), + Имя(ПолЧеловека), + Отчество(ПолЧеловека) + ); + +КонецФункции + +// Формирует случаный ИНН физического лица +// +// Возвращаемое значение: +// Строка +Функция ИНН() Экспорт + Возврат ЮТТестовыеДанные.Подражатель().Компании().ИНН(, Истина); +КонецФункции + +// Формирует случаный СНИЛС. +// https://ru.wikipedia.org/wiki/Контрольное_число +// Возвращаемое значение: +// Строка +Функция СНИЛС() Экспорт + ЧастиСнилс = Новый Массив(); + ФорматаяСтрока = "ЧЦ=3; ЧН=000; ЧВН=;"; + ЧастиСнилс.Добавить(Формат(ЮТТестовыеДанные.СлучайноеЧисло(100, 999), ФорматаяСтрока)); + ЧастиСнилс.Добавить(Формат(ЮТТестовыеДанные.СлучайноеЧисло(0, 999), ФорматаяСтрока)); + ЧастиСнилс.Добавить(Формат(ЮТТестовыеДанные.СлучайноеЧисло(0, 999), ФорматаяСтрока)); + + ИтогоСтрокой = СтрСоединить(ЧастиСнилс, ""); + ДлинаОсновнойЧасти = СтрДлина(ИтогоСтрокой); + Сумма = 0; + Для Итератор = 0 По 8 Цикл + Сумма = Сумма + (Число(Сред(ИтогоСтрокой, ДлинаОсновнойЧасти - Итератор, 1)) * (Итератор + 1)); + КонецЦикла; + + ОстатокОтДеления = Сумма % 101; + КонтрольноеЧисло = ?(ОстатокОтДеления = 100, 0, ОстатокОтДеления); + + Возврат СтрШаблон( + "%1-%2-%3 %4", + ЧастиСнилс[0], + ЧастиСнилс[1], + ЧастиСнилс[2], + Формат(КонтрольноеЧисло, "ЧЦ=2; ЧН=00; ЧВН=;") + ); + +КонецФункции + +#Область ФабрикаПеречислений + +// Варианты биологического пола человека (не путать с гендером) +// +// Возвращаемое значение: +// ФиксированнаяСтруктура - Пол человека: +// * Мужской - Строка - +// * Женский - Строка - +Функция ПолЧеловека() Экспорт + + Результат = Новый Структура(); + Результат.Вставить("Мужской", "Мужской"); + Результат.Вставить("Женский", "Женский"); + Возврат Новый ФиксированнаяСтруктура(Результат); + +КонецФункции + +#КонецОбласти + +#КонецОбласти + +#Область СлужебныеПроцедурыИФункции + +Функция ИмяРеализации() + Возврат "Люди"; +КонецФункции + +Функция СловарьЖенскиеИмена() + Возврат ЮТПодражательСлужебный.Словарь(ИмяРеализации(), "ЖенскиеИмена"); +КонецФункции +Функция СловарьЖенскиеФамилии() + Возврат ЮТПодражательСлужебный.Словарь(ИмяРеализации(), "ЖенскиеФамилии"); +КонецФункции +Функция СловарьЖенскиеОтчества() + Возврат ЮТПодражательСлужебный.Словарь(ИмяРеализации(), "ЖенскиеОтчества"); +КонецФункции + +Функция СловарьМужскиеИмена() + Возврат ЮТПодражательСлужебный.Словарь(ИмяРеализации(), "МужскиеИмена"); +КонецФункции +Функция СловарьМужскиеФамилии() + Возврат ЮТПодражательСлужебный.Словарь(ИмяРеализации(), "МужскиеФамилии"); +КонецФункции +Функция СловарьМужскиеОтчества() + Возврат ЮТПодражательСлужебный.Словарь(ИмяРеализации(), "МужскиеОтчества"); +КонецФункции + +Функция ОпределитьПолЧеловекаИзПараметра(Пол) + + Если Пол <> Неопределено Тогда + Если Не ПолЧеловека().Свойство(Пол) Тогда + ВызватьИсключение СтрШаблон("Отсутствует реализация словаря для пола: %1", Пол); + КонецЕсли; + Возврат Пол; + КонецЕсли; + + Варианты = ЮТКоллекции.ВыгрузитьЗначения(ПолЧеловека(), "Значение"); + + Возврат ЮТТестовыеДанные.СлучайноеЗначениеИзСписка(Варианты); +КонецФункции + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТПодражательСлужебный.xml b/src/cfe/YAXUnit/CommonModules/ЮТПодражательСлужебный.xml new file mode 100644 index 0000000..2e52d1d --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТПодражательСлужебный.xml @@ -0,0 +1,23 @@ + + + + + ЮТПодражательСлужебный + + + ru + Подражатель служебный + + + + false + true + true + false + true + false + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТПодражательСлужебный/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТПодражательСлужебный/Ext/Module.bsl new file mode 100644 index 0000000..a0936b0 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТПодражательСлужебный/Ext/Module.bsl @@ -0,0 +1,87 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область СлужебныйПрограммныйИнтерфейс + +// Получает список из словаря с учетом установленной локализации +// +// Параметры: +// ИмяРеализации - Строка - Имя реализации +// ИмяСловаря - Строка - Имя словаря +// КодЛокализации - Строка - Код локализации, по умолчанию берется из контекста +// +// Возвращаемое значение: +// ФиксированныйМассив из Строка +Функция Словарь(ИмяРеализации, ИмяСловаря, Знач КодЛокализации = Неопределено) Экспорт + КодЛокализации = ?(КодЛокализации = Неопределено, ЮТПодражатель.Локализация(), КодЛокализации); + Возврат ЮТПодражательСлужебныйПовтИсп.Словарь(ИмяРеализации, ИмяСловаря, КодЛокализации); +КонецФункции + +// Случайное значение из словаря. +// +// Параметры: +// Словарь - Массив из Строка - Словарь +// +// Возвращаемое значение: +// - Строка +Функция СлучайноеЗначениеИзСловаря(Словарь) Экспорт + Возврат Словарь.Получить(ЮТТестовыеДанные.СлучайноеЧисло(0, Словарь.ВГраница())); +КонецФункции + +// Контекст. +// +// Возвращаемое значение: +// см. НовыйКонтекст +Функция Контекст() Экспорт + //@skip-check constructor-function-return-section + Возврат ЮТКонтекстСлужебный.ЗначениеКонтекста(КлючКонтекста()); +КонецФункции + +// Инициализирует подражатель +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция Инициализировать() Экспорт + Если Контекст() = Неопределено Тогда + ЮТКонтекстСлужебный.УстановитьЗначениеКонтекста(КлючКонтекста(), НовыйКонтекст()); + КонецЕсли; + Возврат ЮТПодражатель; +КонецФункции + +#КонецОбласти + +#Область СлужебныеПроцедурыИФункции + +Функция КлючКонтекста() + Возврат "Подражатель"; +КонецФункции + +// Новый контекст. +// +// Возвращаемое значение: +// Структура - Новый контекст: +// * Локализация - см. ЮТЛокальСлужебный.ЛокальИнтерфейса +Функция НовыйКонтекст() + + Описание = Новый Структура; + Описание.Вставить("Локализация", ЮТЛокальСлужебный.ЛокальИнтерфейса()); + Возврат Описание; + +КонецФункции + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТПодражательСлужебныйВызовСервера.xml b/src/cfe/YAXUnit/CommonModules/ЮТПодражательСлужебныйВызовСервера.xml new file mode 100644 index 0000000..34d70b7 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТПодражательСлужебныйВызовСервера.xml @@ -0,0 +1,23 @@ + + + + + ЮТПодражательСлужебныйВызовСервера + + + ru + Подражатель вызов сервера + + + + false + false + true + false + false + true + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТПодражательСлужебныйВызовСервера/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТПодражательСлужебныйВызовСервера/Ext/Module.bsl new file mode 100644 index 0000000..781bcd5 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТПодражательСлужебныйВызовСервера/Ext/Module.bsl @@ -0,0 +1,38 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область СлужебныйПрограммныйИнтерфейс + +// Данные словаря. +// +// Параметры: +// Кодификатор - Строка - Имя словаря в метаданных +// +// Возвращаемое значение: +// ФиксированныйМассив из Строка +Функция ДанныеСловаря(Кодификатор) Экспорт + Если Метаданные.ОбщиеМакеты.Найти(Кодификатор) = Неопределено Тогда + ВызватьИсключение СтрШаблон("Словарь с именем (%1) не найден", Кодификатор); + КонецЕсли; + + Макет = ПолучитьОбщийМакет(Кодификатор); + Возврат СтрРазделить(Макет.ПолучитьТекст(), Символы.ПС, Ложь); + +КонецФункции + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТПодражательСлужебныйПовтИсп.xml b/src/cfe/YAXUnit/CommonModules/ЮТПодражательСлужебныйПовтИсп.xml new file mode 100644 index 0000000..f4e5672 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТПодражательСлужебныйПовтИсп.xml @@ -0,0 +1,23 @@ + + + + + ЮТПодражательСлужебныйПовтИсп + + + ru + Подражатель повт исп + + + + false + true + true + true + true + false + false + DuringSession + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТПодражательСлужебныйПовтИсп/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТПодражательСлужебныйПовтИсп/Ext/Module.bsl new file mode 100644 index 0000000..366db1d --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТПодражательСлужебныйПовтИсп/Ext/Module.bsl @@ -0,0 +1,48 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область СлужебныйПрограммныйИнтерфейс + +// Получает список из словаря с учетом установленной локализации +// +// Параметры: +// ИмяРеализации - Строка - Имя реализации +// ИмяСловаря - Строка - Имя словаря +// КодЛокализации - Строка - Код локализации +// +// Возвращаемое значение: +// ФиксированныйМассив из Строка +Функция Словарь(ИмяРеализации, ИмяСловаря, КодЛокализации) Экспорт + Кодификатор = КодификаторСловаря(ИмяРеализации, ИмяСловаря, КодЛокализации); + Возврат Новый ФиксированныйМассив(ЮТПодражательСлужебныйВызовСервера.ДанныеСловаря(Кодификатор)); +КонецФункции + +#КонецОбласти + +#Область СлужебныеПроцедурыИФункции + +Функция КодификаторСловаря(ИмяРеализации, ИмяСловаря, КодЛокализации) + Возврат СтрШаблон( + "ЮТ_СловарьПодражателя_%1_%2_%3", + ИмяРеализации, + ИмяСловаря, + КодЛокализации + ); +КонецФункции + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТПредикаты.xml b/src/cfe/YAXUnit/CommonModules/ЮТПредикаты.xml new file mode 100644 index 0000000..1535867 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТПредикаты.xml @@ -0,0 +1,23 @@ + + + + + ЮТПредикаты + + + ru + Предикаты + + + + false + true + true + false + true + false + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТПредикаты/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТПредикаты/Ext/Module.bsl new file mode 100644 index 0000000..ec10021 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТПредикаты/Ext/Module.bsl @@ -0,0 +1,440 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +///////////////////////////////////////////////////////////////////////////////// +// Механизм предикатов позволяет: +// +// * Формировать наборы утверждений и передавать в методы проверки +// * Методы для формирования предикатов имеют такой же синтаксис как и утверждения для тестов см. ЮТест.ОжидаетЧто +// * Проверять элементы коллекций на соответствие утверждениям +///////////////////////////////////////////////////////////////////////////////// +#Область ПрограммныйИнтерфейс + +// Устанавливает имя реквизита, все последующие проверки будут относится к нему. +// +// Параметры: +// ИмяРеквизита - Строка - Имя реквизита +// - Число - Индекс коллекции +// - Произвольный - Ключ соответствия +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция Реквизит(ИмяРеквизита) Экспорт + + Контекст().ИмяРеквизита = ИмяРеквизита; + Возврат ЮТПредикаты; + +КонецФункции + +// Устанавливает имя свойства, все последующие проверки будут относится к нему. +// Это алиас для см. Реквизит +// +// Параметры: +// ИмяСвойства - Строка - Имя реквизита +// - Число - Индекс коллекции +// - Произвольный - Ключ соответствия +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция Свойство(ИмяСвойства) Экспорт + + Возврат Реквизит(ИмяСвойства); + +КонецФункции + +// Добавляет предикат, проверяющий равенство объекта (свойства) указанному значению +// +// Параметры: +// Значение - Произвольный +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция Равно(Значение) Экспорт + + ДобавитьПредикат(Выражения().Равно, Значение); + Возврат ЮТПредикаты; + +КонецФункции + +// Добавляет предикат, проверяющий не равенство объекта (свойства) указанному значению +// +// Параметры: +// Значение - Произвольный +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция НеРавно(Значение) Экспорт + + ДобавитьПредикат(Выражения().НеРавно, Значение); + Возврат ЮТПредикаты; + +КонецФункции + +// Добавляет предикат, проверяющий заполненность объекта (свойства) +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция Заполнено() Экспорт + + ДобавитьПредикат(Выражения().Заполнено, Неопределено); + Возврат ЮТПредикаты; + +КонецФункции + +// Добавляет предикат, проверяющий, что объект (свойств) не заполнено +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция Пусто() Экспорт + + ДобавитьПредикат(Выражения().НеЗаполнено, Неопределено); + Возврат ЮТПредикаты; + +КонецФункции + +// Добавляет предикат, проверяющий, что значение объекта (свойства) больше указанного +// +// Параметры: +// Значение - Произвольный +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция Больше(Значение) Экспорт + + ДобавитьПредикат(Выражения().Больше, Значение); + Возврат ЮТПредикаты; + +КонецФункции + +// Добавляет предикат, проверяющий, что значение объекта (свойства) больше или равно указанному +// +// Параметры: +// Значение - Произвольный +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция БольшеИлиРавно(Значение) Экспорт + + ДобавитьПредикат(Выражения().БольшеРавно, Значение); + Возврат ЮТПредикаты; + +КонецФункции + +// Добавляет предикат, проверяющий, что значение объекта (свойства) меньше указанного +// +// Параметры: +// Значение - Произвольный +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция Меньше(Значение) Экспорт + + ДобавитьПредикат(Выражения().Меньше, Значение); + Возврат ЮТПредикаты; + +КонецФункции + +// Добавляет предикат, проверяющий, что значение объекта (свойства) меньше или равно указанному +// +// Параметры: +// Значение - Произвольный +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция МеньшеИлиРавно(Значение) Экспорт + + ДобавитьПредикат(Выражения().МеньшеРавно, Значение); + Возврат ЮТПредикаты; + +КонецФункции + +// Добавляет предикат, проверяющий, что значение объекта (свойства) имеет указанный тип +// +// Параметры: +// Тип - Тип +// - ОписаниеТипов +// - Строка - Имя типа +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция ИмеетТип(Тип) Экспорт + + ДобавитьПредикат(Выражения().ИмеетТип, Тип); + Возврат ЮТПредикаты; + +КонецФункции + +// Добавляет предикат, проверяющий, что значение объекта (свойства) имеет тип отличный от указанного +// +// Параметры: +// Тип - Тип +// - ОписаниеТипов +// - Строка - Имя типа +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция ИмеетТипОтличныйОт(Тип) Экспорт + + ДобавитьПредикат(Выражения().НеИмеетТип, Тип); + Возврат ЮТПредикаты; + +КонецФункции + +// Добавляет предикат, проверяющий, длину/размер значение объекта (свойства) на равенство указанному значению +// +// Параметры: +// Значение - Произвольный +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция ИмеетДлину(Значение) Экспорт + + ДобавитьПредикат(Выражения().ИмеетДлину, Значение); + Возврат ЮТПредикаты; + +КонецФункции + +// Добавляет предикат, проверяющий, длину/размер значение объекта (свойства) на не равенство указанному значению +// +// Параметры: +// Значение - Произвольный +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция ИмеетДлинуОтличнуюОт(Значение) Экспорт + + ДобавитьПредикат(Выражения().НеИмеетДлину, Значение); + Возврат ЮТПредикаты; + +КонецФункции + +// Добавляет предикат, проверяющий, что значение объекта (реквизита) содержит вложенное свойство +// +// Параметры: +// ИмяСвойства - Строка - Имя свойства +// - Число - Индекс коллекции +// - Произвольный - Ключ соответствия +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция ИмеетСвойство(ИмяСвойства) Экспорт + + ДобавитьПредикат(Выражения().ИмеетСвойство, ИмяСвойства); + Возврат ЮТПредикаты; + +КонецФункции + +// Добавляет предикат, проверяющий, что значение объекта (реквизита) не содержит вложенное свойство +// +// Параметры: +// ИмяСвойства - Строка - Имя свойства +// - Число - Индекс коллекции +// - Произвольный - Ключ соответствия +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция НеИмеетСвойства(ИмяСвойства) Экспорт + + ДобавитьПредикат(Выражения().НеИмеетСвойство, ИмяСвойства); + Возврат ЮТПредикаты; + +КонецФункции + +// Добавляет предикат, проверяющий, что значение объекта (реквизита) содержит указанное значение +// +// Параметры: +// Значение - Произвольный +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция Содержит(Значение) Экспорт + + ДобавитьПредикат(Выражения().Содержит, Значение); + Возврат ЮТПредикаты; + +КонецФункции + +// Добавляет предикат, проверяющий, что значение объекта (реквизита) не содержит указанное значение +// +// Параметры: +// Значение - Произвольный +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция НеСодержит(Значение) Экспорт + + ДобавитьПредикат(Выражения().НеСодержит, Значение); + Возврат ЮТПредикаты; + +КонецФункции + +// Добавляет предикат, проверяющий, что строка соответствует указанному регулярному выражению +// +// Параметры: +// Значение - Строка +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция СодержитСтрокуПоШаблону(Значение) Экспорт + + ДобавитьПредикат(Выражения().СодержитСтрокуПоШаблону, Значение); + Возврат ЮТПредикаты; + +КонецФункции + +// Добавляет предикат, проверяющий, что строка не соответствует указанному регулярному выражению +// +// Параметры: +// Значение - Строка +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция НеСодержитСтрокуПоШаблону(Значение) Экспорт + + ДобавитьПредикат(Выражения().НеСодержитСтрокуПоШаблону, Значение); + Возврат ЮТПредикаты; + +КонецФункции + +// Добавляет условие, что проверяемое значение (или значение его свойства) входит в список значений +// +// Параметры: +// Значения - Массив из Произвольный - Значения для проверки +// - СписокЗначений из Произвольный - Значения для проверки +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция ВСписке(Значения) Экспорт + + ДобавитьПредикат(Выражения().ВСписке, Значения); + Возврат ЮТПредикаты; + +КонецФункции + +// Возвращает набор сформированных утверждений. +// +// Рекомендуется использовать этот метод, если планируется отложенная проверка предикатов. Например, вы хотите сформировать два набору предикатов +// и проверять их в зависимости от условия. +// +// Метод копирует настроенный набор утверждений в массив и возвращает его, таким образом сохраняется состояние, которое можно передавать дальше. +// +// Возвращаемое значение: +// Массив из см. ЮТФабрика.ВыражениеПредиката - Набор предикатов +Функция Получить() Экспорт + + Возврат ЮТКоллекции.СкопироватьМассив(Контекст().Предикаты); + +КонецФункции + +#КонецОбласти + +#Область СлужебныеПроцедурыИФункции + +// Инициализирует конструктор предиката +// Параметры: +// Условия - Структура, Соответствие из Произвольный - Набор условий, которыми инициализируется предикат +// Ключ - Строка - Имя реквизита +// Значение - Произвольный - Значение, которому должен быть равен реквизит +// +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция Инициализировать(Условия = Неопределено) Экспорт + + ЮТКонтекстСлужебный.УстановитьЗначениеКонтекста(КлючКонтекста(), НовыйКонтекст()); + + Если ЗначениеЗаполнено(Условия) Тогда + Для Каждого Элемент Из Условия Цикл + Реквизит(Элемент.Ключ).Равно(Элемент.Значение); + КонецЦикла; + КонецЕсли; + + Возврат ЮТПредикаты; + +КонецФункции + +Функция Выражения() Экспорт + + Выражения = Новый Структура; + Выражения.Вставить("Равно", "Равно"); + Выражения.Вставить("НеРавно", "НеРавно"); + Выражения.Вставить("Заполнено", "Заполнено"); + Выражения.Вставить("НеЗаполнено", "НеЗаполнено"); + Выражения.Вставить("Больше", "Больше"); + Выражения.Вставить("БольшеРавно", "БольшеРавно"); + Выражения.Вставить("Меньше", "Меньше"); + Выражения.Вставить("МеньшеРавно", "МеньшеРавно"); + Выражения.Вставить("ИмеетТип", "ИмеетТип"); + Выражения.Вставить("НеИмеетТип", "НеИмеетТип"); + Выражения.Вставить("ИмеетДлину", "ИмеетДлину"); + Выражения.Вставить("НеИмеетДлину", "НеИмеетДлину"); + Выражения.Вставить("ИмеетСвойство", "ИмеетСвойство"); + Выражения.Вставить("НеИмеетСвойство", "НеИмеетСвойство"); + Выражения.Вставить("Содержит", "Содержит"); + Выражения.Вставить("НеСодержит", "НеСодержит"); + Выражения.Вставить("СодержитСтрокуПоШаблону", "СодержитСтрокуПоШаблону"); + Выражения.Вставить("НеСодержитСтрокуПоШаблону", "НеСодержитСтрокуПоШаблону"); + Выражения.Вставить("ВСписке", "ВСписке"); + + Возврат Новый ФиксированнаяСтруктура(Выражения); + +КонецФункции + +// Контекст. +// +// Возвращаемое значение: +// см. НовыйКонтекст +Функция Контекст() + + //@skip-check constructor-function-return-section + Возврат ЮТКонтекстСлужебный.ЗначениеКонтекста(КлючКонтекста()); + +КонецФункции + +Функция КлючКонтекста() + + Возврат "Предикаты"; + +КонецФункции + +// Новый контекст. +// +// Возвращаемое значение: +// Структура - Новый контекст: +// * Предикаты - Массив из см. Предикат - Зарегистрированные предикаты +// * ИмяРеквизита - Неопределено, Строка - Имя проверяемого реквизита +Функция НовыйКонтекст() + + Описание = Новый Структура(); + Описание.Вставить("Предикаты", Новый Массив()); + Описание.Вставить("ИмяРеквизита", Неопределено); + + Возврат Описание; + +КонецФункции + +Процедура ДобавитьПредикат(ВидСравнения, Значение) + + Контекст = Контекст(); + + Предикат = ЮТФабрика.ВыражениеПредиката(ВидСравнения, Контекст.ИмяРеквизита, Значение); + Контекст.Предикаты.Добавить(Предикат); + +КонецПроцедуры + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТПредикатыСлужебныйКлиентСервер.xml b/src/cfe/YAXUnit/CommonModules/ЮТПредикатыСлужебныйКлиентСервер.xml new file mode 100644 index 0000000..2315dc0 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТПредикатыСлужебныйКлиентСервер.xml @@ -0,0 +1,23 @@ + + + + + ЮТПредикатыСлужебныйКлиентСервер + + + ru + Предикаты клиент сервер + + + + false + true + true + false + true + false + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТПредикатыСлужебныйКлиентСервер/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТПредикатыСлужебныйКлиентСервер/Ext/Module.bsl new file mode 100644 index 0000000..67d24a9 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТПредикатыСлужебныйКлиентСервер/Ext/Module.bsl @@ -0,0 +1,235 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область СлужебныйПрограммныйИнтерфейс + +// Проверить предикат. +// +// Параметры: +// Значение - Произвольный +// Предикаты - Массив Из см. ЮТФабрика.ВыражениеПредиката +// ПараметрыСообщенийОбОшибке - см. ПараметрыСообщенийОбОшибке +// ПараметрыСравнения - Неопределено +// - Структура - Параметры сравнения значений, для разных выражений испльзуются свои параметры +// +// Возвращаемое значение: +// см. ЮТФабрикаСлужебный.ОписаниеРезультатаПроверки +Функция ПроверитьПредикаты(Знач Значение, Знач Предикаты, Знач ПараметрыСообщенийОбОшибке = Неопределено, ПараметрыСравнения = Неопределено) Экспорт + + Результат = ЮТФабрикаСлужебный.ОписаниеРезультатаПроверки(); + + Если ПараметрыСообщенийОбОшибке = Неопределено Тогда + ПараметрыСообщенийОбОшибке = ПараметрыСообщенийОбОшибке(); + КонецЕсли; + + Предикаты = НаборПредикатов(Предикаты); + Для Каждого Выражение Из Предикаты Цикл + + ЮТСравнениеСлужебныйКлиентСервер.ПроверитьВыражениеПредиката(Значение, Выражение, Результат, ПараметрыСообщенийОбОшибке, ПараметрыСравнения); + Если НЕ Результат.Успешно Тогда + Прервать; + КонецЕсли; + + КонецЦикла; + + Возврат Результат; + +КонецФункции + +// Набор предикатов. +// +// Параметры: +// Предикаты - Массив из см. ЮТФабрика.ВыражениеПредиката - Набор утверждений. см. ЮТест.Предикат +// - см. ЮТФабрика.ВыражениеПредиката +// - CommonModule.ЮТПредикаты - Модуль настройки предикатов, см. ЮТест.Предикат +// +// Возвращаемое значение: +// Массив из см. ЮТФабрика.ВыражениеПредиката - Набор предикатов +Функция НаборПредикатов(Знач Предикаты) Экспорт + + ТипПараметра = ТипЗнч(Предикаты); + + Если ЭтоПредикатОбщийМодуль(ТипПараметра, Предикаты) Тогда + Результат = ЮТПредикаты.Получить(); + ИначеЕсли ЭтоПредикатМассив(ТипПараметра, Предикаты) Тогда + Результат = Предикаты; + ИначеЕсли ЭтоПредикатСтруктура(ТипПараметра, Предикаты) Тогда + Результат = ЮТКоллекции.ЗначениеВМассиве(Предикаты); + Иначе + ВызватьИсключение ЮТИсключения.НекорректныеПараметрыМетода("ЮТПредикатыКлиентСервер.НаборПредикатов"); + КонецЕсли; + + Возврат Результат; + +КонецФункции + +// Это предикат +// +// Параметры: +// Предикаты - Произвольный - значение, для которого будет определено является ли оно предикатом или нет +// +// Возвращаемое значение: +// Булево +Функция ЭтоПредикат(Предикаты) Экспорт + + ТипПараметра = ТипЗнч(Предикаты); + + Возврат ЭтоПредикатОбщийМодуль(ТипПараметра, Предикаты) + ИЛИ ЭтоПредикатМассив(ТипПараметра, Предикаты) + ИЛИ ЭтоПредикатСтруктура(ТипПараметра, Предикаты); + +КонецФункции + +Функция ПредставлениеПредикатов(Знач Предикаты, Разделитель, ШаблонСвойства = "содержит свойство `%1`, которое") Экспорт + + Представления = Новый Массив(); + Предикаты = НаборПредикатов(Предикаты); + ИмяРеквизита = Неопределено; + Для Каждого Выражение Из Предикаты Цикл + НеДобавлятьИмяРеквизита = ИмяРеквизита = Выражение.ИмяРеквизита; + ИмяРеквизита = Выражение.ИмяРеквизита; + Представления.Добавить(ПредставлениеПредиката(Выражение, ШаблонСвойства, НеДобавлятьИмяРеквизита)); + КонецЦикла; + + Возврат СтрСоединить(Представления, Разделитель); + +КонецФункции + +Функция ШаблонВыражения(Знач Выражение) Экспорт + + Отрицание = СтрНачинаетсяС(Выражение, "Не"); + Если Отрицание Тогда + Выражение = Сред(Выражение, 3); + КонецЕсли; + + Выражения = ЮТПредикаты.Выражения(); + + Шаблон = Неопределено; + Если Выражение = Выражения.Равно Тогда + Шаблон = "равно %1"; + ИначеЕсли Выражение = Выражения.Заполнено Тогда + Шаблон = "является заполненным"; + ИначеЕсли Выражение = Выражения.Больше Тогда + Шаблон = "больше чем %1"; + ИначеЕсли Выражение = Выражения.БольшеРавно Тогда + Шаблон = "больше или равно %1"; + ИначеЕсли Выражение = Выражения.Меньше Тогда + Шаблон = "меньше чем %1"; + ИначеЕсли Выражение = Выражения.МеньшеРавно Тогда + Шаблон = "меньше или равно %1"; + ИначеЕсли Выражение = Выражения.ИмеетТип Тогда + Шаблон = "имеет тип %1"; + ИначеЕсли Выражение = Выражения.ИмеетДлину Тогда + Шаблон = "имеет длину (размер) %1"; + ИначеЕсли Выражение = Выражения.ИмеетСвойство Тогда + Шаблон = "содержит свойство %1"; + ИначеЕсли Выражение = Выражения.Содержит Тогда + Шаблон = "содержит %1"; + ИначеЕсли Выражение = Выражения.СодержитСтрокуПоШаблону Тогда + Шаблон = "содержит подстроку соответствующую шаблону %1"; + ИначеЕсли Выражение = Выражения.ВСписке Тогда + Шаблон = "в списке %1"; + Иначе + ВызватьИсключение "Не описан шаблон сообщения для выражения предиката " + Выражение; + КонецЕсли; + + Если Отрицание Тогда + Шаблон = "не " + Шаблон; + КонецЕсли; + + Возврат Шаблон; + +КонецФункции + +Функция ЭтоВыраженияОтрицания(Выражение) Экспорт + + Возврат СтрНачинаетсяС(Выражение, "Не"); + +КонецФункции + +Функция ВыраженияБезОтрицания(Выражение) Экспорт + + Возврат Сред(Выражение, 3); + +КонецФункции + +// Параметры сообщений об ошибке. +// +// Параметры: +// ОписаниеПроверки - Строка - Описание конкретной проверки +// ТекстПроверяемоеЗначение - Строка - Человекочитаемое описание проверяемого значения +// ПредставлениеПроверяемогоЗначения - Неопределено - Представление проверяемого значения +// +// Возвращаемое значение: +// Структура - Параметры сообщений об ошибке: +// * ОписаниеПроверки - Неопределено, Строка - Описание конкретной проверки +// * ТекстПроверяемоеЗначение - Неопределено, Строка - Человекочитаемое описание проверяемого значения +// * ПредставлениеПроверяемогоЗначения - Неопределено, Строка - +Функция ПараметрыСообщенийОбОшибке(ОписаниеПроверки = Неопределено, + ТекстПроверяемоеЗначение = "проверяемое значение", + ПредставлениеПроверяемогоЗначения = Неопределено) Экспорт + + Параметры = Новый Структура; + Параметры.Вставить("ОписаниеПроверки", ОписаниеПроверки); + Параметры.Вставить("ТекстПроверяемоеЗначение", ТекстПроверяемоеЗначение); + Параметры.Вставить("ПредставлениеПроверяемогоЗначения", ПредставлениеПроверяемогоЗначения); + + Возврат Параметры; + +КонецФункции + +#КонецОбласти + +#Область СлужебныеПроцедурыИФункции + +Функция ПредставлениеПредиката(ВыражениеПредиката, ШаблонСвойства, НеДобавлятьИмяРеквизита) + + Если НеДобавлятьИмяРеквизита ИЛИ ВыражениеПредиката.ИмяРеквизита = Неопределено Тогда + ПроверяемоеЗначение = ""; + Иначе + ПроверяемоеЗначение = СтрШаблон(ШаблонСвойства, ВыражениеПредиката.ИмяРеквизита) + " "; + КонецЕсли; + + Выражение = ЮТСообщенияСлужебный.ПодставитьПредставлениеЗначенияВШаблон(ШаблонВыражения(ВыражениеПредиката.ВидСравнения), + ВыражениеПредиката.Значение); + + Возврат СтрШаблон("%1%2", ПроверяемоеЗначение, Выражение); + +КонецФункции + +Функция ЭтоПредикатОбщийМодуль(ТипПредикатов, Предикаты) + + Возврат ТипПредикатов = Тип("ОбщийМодуль") И Предикаты = ЮТПредикаты; + +КонецФункции + +Функция ЭтоПредикатМассив(ТипПредикатов, Предикаты) + + Возврат ТипПредикатов = Тип("Массив") + И Предикаты.Количество() + И ЭтоПредикатСтруктура(ТипЗнч(Предикаты[0]), Предикаты[0]); + +КонецФункции + +Функция ЭтоПредикатСтруктура(ТипПредикатов, Предикаты) + + Возврат ТипПредикатов = Тип("Структура") И ЮТОбщий.ТипСтруктуры(Предикаты) = "Предикат"; + +КонецФункции + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТПреобразованияСлужебный.xml b/src/cfe/YAXUnit/CommonModules/ЮТПреобразованияСлужебный.xml new file mode 100644 index 0000000..7111d62 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТПреобразованияСлужебный.xml @@ -0,0 +1,23 @@ + + + + + ЮТПреобразованияСлужебный + + + ru + Преобразования + + + + false + false + true + false + false + false + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТПреобразованияСлужебный/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТПреобразованияСлужебный/Ext/Module.bsl new file mode 100644 index 0000000..7b36a3c --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТПреобразованияСлужебный/Ext/Module.bsl @@ -0,0 +1,230 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область СлужебныйПрограммныйИнтерфейс + +// Читает табличный документ в массив структур +// +// Параметры: +// ТабличныйДокумент - ТабличныйДокумент - Исходный табличный документ +// НомерКолонки - Число - Номер строки таблицы, с которой следует начать считывание +// НомерСтроки - Число - Номер колонки таблицы, с которой следует начать считывание +// Возвращаемое значение: +// Массив из Структура - Данные табличного документа +Функция ДанныеТабличногоДокумента(ТабличныйДокумент, Знач НомерКолонки = 1, Знач НомерСтроки = 1) Экспорт + + МассивДанных = Новый Массив; + СведенияКолонок = Новый Массив; + + ЗаменяемыеСтроки = ЮТТестовыеДанныеСлужебный.ПодстрокиДляЗаменыВИменахСвойств(); + + ЗначениеКолонки = ТабличныйДокумент.Область(НомерСтроки, НомерКолонки).Текст; + Пока ЗначениеЗаполнено(ЗначениеКолонки) Цикл + + Для Каждого Замена Из ЗаменяемыеСтроки Цикл + ПодстрокаПоиска = Замена.Ключ; + ПодстрокаЗамены = Замена.Значение; + ИмяКолонки = СтрЗаменить(ЗначениеКолонки, ПодстрокаПоиска, ПодстрокаЗамены); + КонецЦикла; + + Сведения = Новый Структура("НомерКолонки, ИмяКолонки", НомерКолонки, ИмяКолонки); + СведенияКолонок.Добавить(Сведения); + + НомерКолонки = НомерКолонки + 1; + ЗначениеКолонки = ТабличныйДокумент.Область(НомерСтроки, НомерКолонки).Текст; + + КонецЦикла; + + НомерСтроки = НомерСтроки + 1; + + Пока ЕстьЗначенияВСтроке(ТабличныйДокумент, НомерСтроки, СведенияКолонок) Цикл + + Структура = Новый Структура; + + Для Каждого Сведения Из СведенияКолонок Цикл + Значение = СокрЛП(ТабличныйДокумент.Область(НомерСтроки, Сведения.НомерКолонки).Текст); + Структура.Вставить(Сведения.ИмяКолонки, Значение); + КонецЦикла; + + МассивДанных.Добавить(Структура); + + НомерСтроки = НомерСтроки + 1; + + КонецЦикла; + + Возврат МассивДанных; + +КонецФункции + +Функция ПривестиЗначениеКДате(ОписаниеТипа, Знач Значение) Экспорт + + ДатаМассив = СтрРазделить(Значение, ".,:T-/ "); + + НетВремени = 3; + ЕстьВремя = 7; + Полдень = 12; + + ДлинаДеньМесяц = 2; + ДлинаГод = 4; + + ДатаИзСтроки_ПроверкаДлиныДаты(ДатаМассив.Количество(), НетВремени, ЕстьВремя); + + ///////////////////////////////////////////////////////////////////////////////// + + ДатаИзСтроки_ОбработкаМассиваДаты(ДатаМассив); // если вдруг кто-то забыл вставить что-то между разделителями. + + ДатаИзСтроки_ПроверкаМесяца(ДатаМассив[1]); // проверка месяца, корректно или нет + + Если ДатаМассив.Количество() = ЕстьВремя Тогда // время формата HH:mm:ss tt или H:mm:ss tt + + ВГр = ДатаМассив.ВГраница(); + ПозЧас = 3; + + ДатаМассив[ВГр] = ВРег(ДатаМассив[ВГр]); + ЧасДоп = ?(ДатаМассив[ВГр] = "PM", Полдень, 0); + ДатаМассив.Удалить(ВГр); + + ЧасовВСутках = 24; + // если все-таки решили вписать не существующий формат попробуем его воспринять адекватно. + ДатаМассив[ПозЧас] = Строка(?(Число(ДатаМассив[ПозЧас]) + ЧасДоп >= ЧасовВСутках, ДатаМассив[ПозЧас], Число(ДатаМассив[ПозЧас]) + ЧасДоп)); + + КонецЕсли; + + Для Индекс = 0 По ДатаМассив.ВГраница() Цикл // добавляем ведущие нули в маски d.M.yy, yy.M.d, H:mm:ss + + ДатаМассив[Индекс] = Формат(Число(ДатаМассив[Индекс]), "ЧЦ=" + ?(СтрДлина(ДатаМассив[Индекс]) > ДлинаДеньМесяц, "4", "2") + "; ЧВН=; ЧГ=0; ЧН=00"); + + КонецЦикла; + + ПозГод = 2; + ПозМесяц = 1; + ПозДень = 0; + + // Проверка гггг.мм.дд или дд.мм.гггг + Если СтрДлина(ДатаМассив[ПозГод]) = ДлинаГод Тогда + + ВремДата = ДатаМассив[ПозДень]; + ДатаМассив[ПозДень] = ДатаМассив[ПозГод]; + ДатаМассив[ПозГод] = ВремДата; + + КонецЕсли; + + // обработка масок dd.MM.yy и yy.MM.dd, первая маска в приоритете. + Если СтрДлина(ДатаМассив[0]) = ДлинаДеньМесяц И СтрДлина(ДатаМассив[ПозГод]) = ДлинаДеньМесяц Тогда + + УсловнаяГраница = 66; // что больше, то 20 век, что меньше - 21 + Год = ?(Число(ДатаМассив[ПозГод]) > УсловнаяГраница, "19", "20"); + + Попытка // попытаемся превратить ее в дату + + // Собственно - проверка, попытка получить дату + //@skip-check module-unused-local-variable - Необходима для помещения результата получения даты из строки. + ТестоваяДата = Дата(Год + ДатаМассив[ПозГод] + ДатаМассив[ПозМесяц] + ДатаМассив[ПозДень]); + + ВремДата = ДатаМассив[ПозДень]; + ДатаМассив[ПозДень] = (Год + ДатаМассив[ПозГод]); + ДатаМассив[ПозГод] = ВремДата; + + Исключение // если не получилось, значит маска yy.MM.dd + + ДатаМассив[ПозДень] = (Год + ДатаМассив[ПозДень]); + + КонецПопытки; + + КонецЕсли; + + Результат = ОписаниеТипа.ПривестиЗначение(СтрСоединить(ДатаМассив)); + + Возврат Результат; + +КонецФункции + +Функция ПривестиЗначениеКЧислу(ОписаниеТипа, Знач Значение) Экспорт + + Значение = СтрЗаменить(Значение, ",", "."); + Результат = ОписаниеТипа.ПривестиЗначение(Значение); + Если ЗначениеЗаполнено(Результат) Тогда + Возврат Результат; + КонецЕсли; + + Значение = СтрЗаменить(Значение, " ", ""); + Результат = ОписаниеТипа.ПривестиЗначение(Значение); + + Возврат Результат; + +КонецФункции + +#КонецОбласти + +#Область СлужебныеПроцедурыИФункции + +Функция ЕстьЗначенияВСтроке(ТабличныйДокумент, НомерСтроки, СведенияКолонок) + + ЕстьЗаполненныеЗначения = Ложь; + + Для Каждого Сведения Из СведенияКолонок Цикл + Если ЕстьЗаполненныеЗначения Тогда + Прервать; + КонецЕсли; + НомерКолонки = Сведения.НомерКолонки; + ЕстьЗаполненныеЗначения = ЗначениеЗаполнено(ТабличныйДокумент.Область(НомерСтроки, НомерКолонки).Текст); + КонецЦикла; + + Возврат ЕстьЗаполненныеЗначения; + +КонецФункции + +Процедура ДатаИзСтроки_ПроверкаДлиныДаты(ДлинаСтроки, ДлинаБезВремени = 0, ДлинаСВременем = 0, ДатаСтрока = "") + + Если ДлинаБезВремени = 0 ИЛИ ДлинаСВременем = 0 Тогда + + ДлинаБезВремени = 6; + ДлинаСВременем = 22; + + КонецЕсли; + + // Временные зоны не поддерживаются, однако формат даты в нулевой зоне попадает в допустимую длину других поддерживаемых форматов. + ДлинаДатыВНулевойЗоне = 20; + ЭтоНулеваяЗона = ДлинаСтроки = ДлинаДатыВНулевойЗоне И СтрЗаканчиваетсяНа(ДатаСтрока, "Z"); + + Если ДлинаСтроки < ДлинаБезВремени Или ДлинаСтроки > ДлинаСВременем Или ЭтоНулеваяЗона Тогда + ВызватьИсключение ЮТИсключения.НекорректныеПараметрыМетода("ПривестиЗначениеКДате", "Дата в строке не подходит ни под одну маску."); + КонецЕсли; + +КонецПроцедуры + +Процедура ДатаИзСтроки_ОбработкаМассиваДаты(ДатаМассив) + + Для Индекс = 0 По ДатаМассив.ВГраница() Цикл + + ДатаМассив[Индекс] = ?(СтрДлина(ДатаМассив[Индекс]) = 0, "0", ДатаМассив[Индекс]); + + КонецЦикла; + +КонецПроцедуры + +Процедура ДатаИзСтроки_ПроверкаМесяца(МесяцСтрокой) + + МесяцевВГоду = 12; + Если Число(МесяцСтрокой) > МесяцевВГоду Или Число(МесяцСтрокой) = 0 Тогда + ВызватьИсключение ЮТИсключения.НекорректныеПараметрыМетода("ПривестиЗначениеКДате", "Месяц выходит за границы диапазона."); + КонецЕсли; + +КонецПроцедуры + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТПроверкиСлужебный.xml b/src/cfe/YAXUnit/CommonModules/ЮТПроверкиСлужебный.xml new file mode 100644 index 0000000..c3bf133 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТПроверкиСлужебный.xml @@ -0,0 +1,23 @@ + + + + + ЮТПроверкиСлужебный + + + ru + Проверки служебный + + + + false + true + true + false + true + false + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТПроверкиСлужебный/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТПроверкиСлужебный/Ext/Module.bsl new file mode 100644 index 0000000..1faf6cc --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТПроверкиСлужебный/Ext/Module.bsl @@ -0,0 +1,69 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2023 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область СлужебныйПрограммныйИнтерфейс + +Процедура ПроверитьТипПараметра(Значение, ОжидаемыйТип, ИмяМетода, ИмяПараметра, ЕслиУстановлен = Ложь) Экспорт + + Если ЕслиУстановлен И Значение = Неопределено Тогда + Возврат; + КонецЕсли; + + Соответствует = ТипЗначенияСоответствует(Значение, ОжидаемыйТип); + + Если НЕ Соответствует Тогда + ТекстОшибки = СтрШаблон("Некорректный тип параметра `%1` метода `%2`. Метод принимает `%3`, а получили `%4` (%5)", + ИмяПараметра, + ИмяМетода, + ОжидаемыйТип, + ТипЗнч(Значение), + Значение); + ВызватьИсключение ТекстОшибки; + КонецЕсли; + +КонецПроцедуры + +Функция ТипЗначенияСоответствует(Значение, ОжидаемыйТип) Экспорт + + ТипОжидаемогоТипа = ТипЗнч(ОжидаемыйТип); + + Если ТипОжидаемогоТипа = Тип("Строка") Тогда + Если СтрНайти(ОжидаемыйТип, ",") Тогда + ОжидаемыйТип = Новый ОписаниеТипов(ОжидаемыйТип); + ТипОжидаемогоТипа = Тип("ОписаниеТипов"); + Иначе + ОжидаемыйТип = Тип(ОжидаемыйТип); + ТипОжидаемогоТипа = Тип("Тип"); + КонецЕсли; + КонецЕсли; + + ТипЗначения = ТипЗнч(Значение); + + Если ТипОжидаемогоТипа = Тип("ОписаниеТипов") Тогда + // СодержитТип не подходит, всегда выдает истину если проверяем Тип("Неопределено") + Соответствует = ОжидаемыйТип.Типы().Найти(ТипЗначения) <> Неопределено + И ОжидаемыйТип.ПривестиЗначение(Значение) = Значение; + Иначе + Соответствует = ТипЗначения = ОжидаемыйТип; + КонецЕсли; + + Возврат Соответствует; + +КонецФункции + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТРасширенияСлужебный.xml b/src/cfe/YAXUnit/CommonModules/ЮТРасширенияСлужебный.xml new file mode 100644 index 0000000..a5d10b3 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТРасширенияСлужебный.xml @@ -0,0 +1,23 @@ + + + + + ЮТРасширенияСлужебный + + + ru + Расширения функциональности + + + + false + true + true + false + true + false + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТРасширенияСлужебный/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТРасширенияСлужебный/Ext/Module.bsl new file mode 100644 index 0000000..5e732b7 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТРасширенияСлужебный/Ext/Module.bsl @@ -0,0 +1,64 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область СлужебныйПрограммныйИнтерфейс + +Функция ГенераторыОтчетов() Экспорт + + Возврат МодулиПодсистемы("ЮТФормированиеОтчета"); + +КонецФункции + +Функция ОбработчикиСобытий() Экспорт + + Серверные = Ложь; + Клиентские = Ложь; +#Если Сервер Тогда + Серверные = Истина; +#КонецЕсли + +#Если Клиент Тогда + Клиентские = Истина; +#КонецЕсли + + Возврат ЮТМетаданные.МодулиПодсистемы("ЮТОбработчикиСобытий", Серверные, Клиентские); + +КонецФункции + +#КонецОбласти + +#Область СлужебныеПроцедурыИФункции + +Функция МодулиПодсистемы(ИмяПодсистемы) + + ИменаМодулей = ЮТМетаданные.МодулиПодсистемы(ИмяПодсистемы); + + Модули = Новый Массив(); + + Для Каждого ИмяМодуля Из ИменаМодулей Цикл + + Модуль = ЮТОбщий.Модуль(ИмяМодуля); + Модули.Добавить(Модуль); + + КонецЦикла; + + Возврат Модули; + +КонецФункции + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТРегистрацияОшибок.xml b/src/cfe/YAXUnit/CommonModules/ЮТРегистрацияОшибок.xml new file mode 100644 index 0000000..9bcbfd3 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТРегистрацияОшибок.xml @@ -0,0 +1,23 @@ + + + + + ЮТРегистрацияОшибок + + + ru + Регистрация ошибок + + + + false + true + true + false + true + false + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТРегистрацияОшибок/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТРегистрацияОшибок/Ext/Module.bsl new file mode 100644 index 0000000..69fab23 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТРегистрацияОшибок/Ext/Module.bsl @@ -0,0 +1,36 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область ПрограммныйИнтерфейс + +// Добавляет пяснение возникшей ошибки, которое будет довлено в отчет. +// Используется перед выбросом исключения, чтобы добавить полезной информации об ошибке, но при этом не ломать стек. +// +// Параметры: +// Пояснение - Строка - Пояснение +Процедура ДобавитьПояснениеОшибки(Пояснение) Экспорт + + ЮТРегистрацияОшибокСлужебный.ДобавитьПояснениеОшибки(Пояснение); + +КонецПроцедуры + +#КонецОбласти + +#Область СлужебныеПроцедурыИФункции + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТРегистрацияОшибокСлужебный.xml b/src/cfe/YAXUnit/CommonModules/ЮТРегистрацияОшибокСлужебный.xml new file mode 100644 index 0000000..e240ebf --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТРегистрацияОшибокСлужебный.xml @@ -0,0 +1,23 @@ + + + + + ЮТРегистрацияОшибокСлужебный + + + ru + Регистрация ошибок + + + + false + true + true + false + true + false + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТРегистрацияОшибокСлужебный/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТРегистрацияОшибокСлужебный/Ext/Module.bsl new file mode 100644 index 0000000..8f3af48 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТРегистрацияОшибокСлужебный/Ext/Module.bsl @@ -0,0 +1,698 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область СлужебныйПрограммныйИнтерфейс + +#Область ФиксацияОшибокВРезультате + +// Регистрирует ошибку обработки события исполнения тестов +// +// Параметры: +// ИмяСобытия - Строка +// ОписаниеСобытия - см. ЮТФабрикаСлужебный.ОписаниеСобытияИсполненияТестов +// Ошибка - ИнформацияОбОшибке +// - Строка +Процедура ЗарегистрироватьОшибкуСобытияИсполнения(ИмяСобытия, ОписаниеСобытия, Ошибка) Экспорт + + ТипОшибки = ЮТФабрикаСлужебный.ТипыОшибок().ОшибкаОбработкиСобытия; + Пояснение = ЮТСообщенияСлужебный.СообщениеОбОшибкеСобытия(ИмяСобытия, Ошибка); + ДанныеОшибки = ДанныеОшибки(Ошибка, Пояснение, ТипОшибки); + + Если ОписаниеСобытия.Тест <> Неопределено Тогда + Объект = ОписаниеСобытия.Тест; + ИначеЕсли ОписаниеСобытия.Набор <> Неопределено Тогда + Объект = ОписаниеСобытия.Набор; + Иначе + Объект = ОписаниеСобытия.Модуль; + КонецЕсли; + + Объект.Ошибки.Добавить(ДанныеОшибки); + +КонецПроцедуры + +// Регистрирует ошибку загрузки тестов +// +// Параметры: +// Объект - Структура - см. ЮТФабрикаСлужебный.ОписаниеТестовогоМодуля или см. ЮТФабрикаСлужебный.ОписаниеТестовогоНабора или см. ЮТФабрикаСлужебный.ОписаниеТеста +// Описание - Строка - Описания ошибки, места возникновения +// Ошибка - ИнформацияОбОшибке +Процедура ЗарегистрироватьОшибкуЧтенияТестов(Объект, Описание, Ошибка) Экспорт + + ДанныеОшибки = ДанныеОшибки(Ошибка, Описание, ЮТФабрикаСлужебный.ТипыОшибок().ЧтенияТестов); + Объект.Ошибки.Добавить(ДанныеОшибки); + +КонецПроцедуры + +// Регистрирует ошибку выполнения теста +// Параметры: +// Тест - см. ЮТФабрикаСлужебный.ОписаниеИсполняемогоТеста +// Ошибка - ИнформацияОбОшибке +Процедура ЗарегистрироватьОшибкуВыполненияТеста(Тест, Ошибка) Экспорт + + ТипОшибки = ТипОшибки(Ошибка, Тест.ПолноеИмяМетода); + + Если ТипОшибки = ЮТФабрикаСлужебный.ТипыОшибок().Утверждений Тогда + ДанныеОшибки = ДанныеОшибкиУтверждений(Ошибка); + ИначеЕсли ТипОшибки = ЮТФабрикаСлужебный.ТипыОшибок().Пропущен Тогда + ДанныеОшибки = ДанныеОшибкиПропуска(Ошибка); + Иначе + ДанныеОшибки = ДанныеОшибки(Ошибка, ЮТСообщенияСлужебный.КраткоеСообщениеОшибки(Ошибка), ТипОшибки); + КонецЕсли; + + Тест.Ошибки.Добавить(ДанныеОшибки); + +КонецПроцедуры + +// Регистрирует ошибку выполнения теста +// Параметры: +// Объект - см. ЮТФабрикаСлужебный.ОписаниеИсполняемогоТеста +// Сообщение - Строка +Процедура ЗарегистрироватьПростуюОшибкуВыполнения(Объект, Сообщение) Экспорт + + ДанныеОшибки = ДанныеОшибки(Неопределено, Сообщение, ЮТФабрикаСлужебный.ТипыОшибок().Исполнения); + Объект.Ошибки.Добавить(ДанныеОшибки); + +КонецПроцедуры + +// Регистрирует ошибку режима выполнения теста +// Параметры: +// Объект - см. ЮТФабрикаСлужебный.ОписаниеИсполняемогоТеста +// Ошибка - Строка +Процедура ЗарегистрироватьОшибкуРежимаВыполнения(Объект, Ошибка) Экспорт + + ДанныеОшибки = ДанныеОшибки(Неопределено, Ошибка, ЮТФабрикаСлужебный.ТипыОшибок().НекорректныйКонтекстИсполнения); + Объект.Ошибки.Добавить(ДанныеОшибки); + +КонецПроцедуры + +#КонецОбласти + +// Вызывает ошибку выполнения теста, на основании перехваченной ошибки +// +// Параметры: +// ИнформацияОбОшибке - ИнформацияОбОшибке +// ОписаниеПроверки - см. ЮТФабрикаСлужебный.ОписаниеПроверки +Процедура СгенерироватьОшибкуВыполнения(ИнформацияОбОшибке, ОписаниеПроверки = Неопределено) Экспорт + + СтруктураОшибки = КонтекстОшибки(); + СтруктураОшибки.ОшибкаУтверждения = Ложь; + + ВызватьОшибкуИсполнения(ИнформацияОбОшибке, ОписаниеПроверки); + +КонецПроцедуры + +// Вызывает ошибку сравнения значений +// При этом сохраняет в контекст состояние, для дальнейшей обработки +// +// Параметры: +// ОписаниеПроверки - см. ЮТФабрикаСлужебный.ОписаниеПроверки +// Сообщение - Строка +// ПроверяемоеЗначение - Произвольный +// ОжидаемоеЗначение - Произвольный +// ОбъектПроверки - Строка - Человекочитаемое описание проверяемого значения +Процедура СгенерироватьОшибкуСравнения(ОписаниеПроверки, + Сообщение, + ПроверяемоеЗначение, + ОжидаемоеЗначение, + ОбъектПроверки = "проверяемое значение") Экспорт + + УстановитьДанныеОшибкиСравнения(ПроверяемоеЗначение, ОжидаемоеЗначение); + ТекстСообщения = ЮТСообщенияСлужебный.ФорматированныйТекстОшибкиУтверждения(ОписаниеПроверки, Сообщение, ОбъектПроверки); + ВызватьОшибкуПроверки(ТекстСообщения, ОписаниеПроверки); + +КонецПроцедуры + +// Вызывает ошибку проверки утверждений +// При этом сохраняет в контекст состояние, для дальнейшей обработки +// +// Параметры: +// ОписаниеПроверки - см. ЮТФабрикаСлужебный.ОписаниеПроверки +// Сообщение - Строка +// ПроверяемоеЗначение - Произвольный +// ОбъектПроверки - Строка - Человекочитаемое описание проверяемого значения +Процедура СгенерироватьОшибкуУтверждения(ОписаниеПроверки, Сообщение, ПроверяемоеЗначение, ОбъектПроверки = "проверяемое значение") Экспорт + + УстановитьДанныеОшибкиУтверждения(ПроверяемоеЗначение); + ТекстСообщения = ЮТСообщенияСлужебный.ФорматированныйТекстОшибкиУтверждения(ОписаниеПроверки, Сообщение, ОбъектПроверки); + ВызватьОшибкуПроверки(ТекстСообщения, ОписаниеПроверки); + +КонецПроцедуры + +Процедура Пропустить(Сообщение) Экспорт + + СтруктураОшибки = КонтекстОшибки(); + СтруктураОшибки.ОшибкаУтверждения = Ложь; + + СообщениеОбОшибке = СообщениеОбОшибке(Сообщение, ПрефиксОшибкиПропуска()); + ВызватьИсключение СообщениеОбОшибке; + +КонецПроцедуры + +Функция ПредставлениеОшибки(Знач Описание, Знач Ошибка) Экспорт + + Если ТипЗнч(Ошибка) = Тип("ИнформацияОбОшибке") Тогда + Ошибка = Символы.ПС + ПодробноеПредставлениеОшибки(Ошибка); + КонецЕсли; + + Возврат СтрШаблон("%1: %2", Описание, Ошибка); + +КонецФункции + +// Вызывает ошибку выполнения теста +// Служебный метод, предварительно нужно самостоятельно настроить контекст (см. ЮТКонтекстСлужебный.КонтекстОшибки) +// Параметры: +// ТекстСообщения - Строка +// ОписаниеПроверки - см. ЮТФабрикаСлужебный.ОписаниеПроверки +Процедура ВызватьОшибкуПроверки(Знач ТекстСообщения, ОписаниеПроверки = Неопределено) Экспорт + + СообщениеОбОшибке = СообщениеОбОшибке(ТекстСообщения, ПрефиксОшибкиУтверждений(), ОписаниеПроверки); + ВызватьИсключение СообщениеОбОшибке; + +КонецПроцедуры + +Процедура ЗарегистрироватьОшибкуИнициализацииДвижка(Ошибка, Описание) Экспорт + + СообщитьОбОшибке(Ошибка, Описание); + +КонецПроцедуры + +// Возвращает тип ошибки +// +// Параметры: +// Ошибка - ИнформацияОбОшибке +// ИмяВызываемогоМетода - Строка - Имя вызываемого метода +// +// Возвращаемое значение: +// Строка - см. ЮТФабрикаСлужебный.ТипыОшибок +Функция ТипОшибки(Ошибка, ИмяВызываемогоМетода) Экспорт + + ТипыОшибок = ЮТФабрикаСлужебный.ТипыОшибок(); + + Описание = Ошибка.Описание; + + ИмяМетода = Сред(ИмяВызываемогоМетода, СтрНайти(ИмяВызываемогоМетода, ".") + 1); + + Тексты = ТекстыОшибокВызоваМетода(ИмяМетода); + + Если Описание = Тексты.МетодНеОбнаружен + И СтрНачинаетсяС(Ошибка.ИсходнаяСтрока, ИмяВызываемогоМетода) Тогда + + ТипОшибки = ТипыОшибок.ТестНеРеализован; + + ИначеЕсли Описание = Тексты.МалоПараметров И СтрНачинаетсяС(Ошибка.ИсходнаяСтрока, ИмяВызываемогоМетода) Тогда + + ТипОшибки = ТипыОшибок.МалоПараметров; + + ИначеЕсли Описание = Тексты.МногоПараметров И СтрНачинаетсяС(Ошибка.ИсходнаяСтрока, ИмяВызываемогоМетода) Тогда + + ТипОшибки = ТипыОшибок.МногоПараметров; + + ИначеЕсли СтрНачинаетсяС(Описание, ПрефиксОшибкиУтверждений()) Тогда + + ТипОшибки = ТипыОшибок.Утверждений; + + ИначеЕсли СтрНачинаетсяС(Описание, ПрефиксОшибкиПропуска()) Тогда + + ТипОшибки = ТипыОшибок.Пропущен; + + Иначе + + ТипОшибки = ТипыОшибок.Исполнения; + + КонецЕсли; + + Возврат ТипОшибки; + +КонецФункции + +Функция ПрефиксОшибкиУтверждений() Экспорт + + Возврат "[Failed]"; + +КонецФункции + +Функция ПрефиксОшибкиВыполнения() Экспорт + + Возврат "[Broken]"; + +КонецФункции + +Функция ПрефиксОшибкиПропуска() Экспорт + + Возврат "[Skip]"; + +КонецФункции + +Функция СтатусВыполненияТеста(Тест) Экспорт + + СтатусыИсполненияТеста = ЮТФабрика.СтатусыИсполненияТеста(); + + Если Тест.Ошибки.КОличество() = 0 Тогда + Возврат СтатусыИсполненияТеста.Успешно; + КонецЕсли; + + ПорядокСтатусов = Новый Массив(); + ПорядокСтатусов.Добавить(СтатусыИсполненияТеста.Успешно); + ПорядокСтатусов.Добавить(СтатусыИсполненияТеста.Исполнение); + ПорядокСтатусов.Добавить(СтатусыИсполненияТеста.НеРеализован); + ПорядокСтатусов.Добавить(СтатусыИсполненияТеста.Ожидание); + ПорядокСтатусов.Добавить(СтатусыИсполненияТеста.Пропущен); + ПорядокСтатусов.Добавить(СтатусыИсполненияТеста.Ошибка); + ПорядокСтатусов.Добавить(СтатусыИсполненияТеста.Сломан); + + Статус = Тест.Статус; + + Для Каждого Ошибка Из Тест.Ошибки Цикл + + СтатусОшибки = СтатусОшибки(Ошибка.ТипОшибки); + + Если ПорядокСтатусов.Найти(СтатусОшибки) > ПорядокСтатусов.Найти(Статус) Тогда + Статус = СтатусОшибки; + КонецЕсли; + + Если Статус = СтатусыИсполненияТеста.Сломан Тогда + Прервать; + КонецЕсли; + + КонецЦикла; + + Возврат Статус; + +КонецФункции + +Функция СтатусОшибки(ТипОшибки) Экспорт + + СтатусОшибки = ЮТФабрикаСлужебный.ПараметрыТиповОшибок()[ТипОшибки].Статус; + + Если СтатусОшибки = Неопределено Тогда + СтатусОшибки = ЮТФабрика.СтатусыИсполненияТеста().Сломан; + КонецЕсли; + + Возврат СтатусОшибки; + +КонецФункции + +Процедура УстановитьДанныеОшибкиСравнения(ПроверяемоеЗначение, ОжидаемоеЗначение) Экспорт + + СтруктураОшибки = КонтекстОшибки(); + + СтруктураОшибки.ОшибкаУтверждения = Истина; + СтруктураОшибки.ПроверяемоеЗначение = ЮТОбщий.ПредставлениеЗначения(ПроверяемоеЗначение); + СтруктураОшибки.ОжидаемоеЗначение = ЮТОбщий.ПредставлениеЗначения(ОжидаемоеЗначение); + +КонецПроцедуры + +Процедура УстановитьДанныеОшибкиУтверждения(ПроверяемоеЗначение) Экспорт + + СтруктураОшибки = КонтекстОшибки(); + + СтруктураОшибки.ОшибкаУтверждения = Истина; + СтруктураОшибки.ПроверяемоеЗначение = ЮТОбщий.ПредставлениеЗначения(ПроверяемоеЗначение); + СтруктураОшибки.ОжидаемоеЗначение = Неопределено; + +КонецПроцедуры + +Функция ДобавитьОписания(ТекстОшибки, ОписаниеПроверки = Неопределено) Экспорт + + Если ОписаниеПроверки <> Неопределено Тогда + ПрефиксОшибки = ЮТСтроки.ДобавитьСтроку(ОписаниеПроверки.ПрефиксОшибки, ОписаниеПроверки.ОписаниеПроверки, " "); + СообщениеОбОшибке = ЮТСтроки.ДобавитьСтроку(ПрефиксОшибки, ТекстОшибки, ": "); + Иначе + СообщениеОбОшибке = ТекстОшибки; + КонецЕсли; + + СообщениеОбОшибке = ВРег(Лев(СообщениеОбОшибке, 1)) + Сред(СообщениеОбОшибке, 2); + Возврат СообщениеОбОшибке; + +КонецФункции + +Процедура ДобавитьОшибкуКРезультатуПроверки(РезультатПроверки, Знач Ошибка, ОписаниеПроверки = Неопределено) Экспорт + + Если ТипЗнч(Ошибка) = Тип("ИнформацияОбОшибке") Тогда + Ошибка = ПодробноеПредставлениеОшибки(Ошибка); + КонецЕсли; + + ТекстОшибки = ДобавитьОписания(Ошибка, ОписаниеПроверки); + РезультатПроверки.Успешно = Ложь; + РезультатПроверки.Сообщения.Добавить(ТекстОшибки); + +КонецПроцедуры + +Процедура ДобавитьОшибкуСравненияКРезультатуПроверки(РезультатПроверки, Сообщение, ПроверяемоеЗначение, ОжидаемоеЗначение) Экспорт + + ОписаниеКонтекстаОшибки = ОписаниеКонтекстаОшибки(); + ОписаниеКонтекстаОшибки.ПроверяемоеЗначение = ПроверяемоеЗначение; + ОписаниеКонтекстаОшибки.ОжидаемоеЗначение = ОжидаемоеЗначение; + ОписаниеКонтекстаОшибки.ОшибкаУтверждения = Истина; + ОписаниеКонтекстаОшибки.Сообщение = Сообщение; + + РезультатПроверки.Успешно = Ложь; + РезультатПроверки.Сообщения.Добавить(ОписаниеКонтекстаОшибки); + +КонецПроцедуры + +Процедура ДобавитьПояснениеОшибки(Пояснение) Экспорт + + Детали = КонтекстДеталиОшибки(); + Установить = Детали = Неопределено; + + Если Установить Тогда + Детали = Новый Массив(); + КонецЕсли; + + Детали.Добавить(Пояснение); + + Если Установить Тогда + ЮТКонтекстСлужебный.УстановитьЗначениеКонтекста(ИмяКонтекстаДеталиОшибки(), Детали); + КонецЕсли; + +КонецПроцедуры + +#КонецОбласти + +#Область СлужебныеПроцедурыИФункции + +#Область Контекст + +// Контекст ошибки. +// +// Возвращаемое значение: +// см. ОписаниеКонтекстаОшибки +Функция КонтекстОшибки() Экспорт + + Контекст = ЮТКонтекстСлужебный.ЗначениеКонтекста(ИмяКонтекстаОшибки()); + + Если Контекст = Неопределено Тогда + Контекст = УстановитьКонтекстОшибки(); + КонецЕсли; + + //@skip-check constructor-function-return-section + Возврат Контекст; + +КонецФункции + +Функция УстановитьКонтекстОшибки() Экспорт + + ДанныеОшибки = ОписаниеКонтекстаОшибки(); + ЮТКонтекстСлужебный.УстановитьЗначениеКонтекста(ИмяКонтекстаОшибки(), ДанныеОшибки); + + Возврат ДанныеОшибки; + +КонецФункции + +Функция КонтекстДеталиОшибки(ПолучитьССервера = Ложь) + + Возврат ЮТКонтекстСлужебный.ЗначениеКонтекста(ИмяКонтекстаДеталиОшибки(), ПолучитьССервера); + +КонецФункции + +// ОписаниеКонтекстаОшибки +// Возвращает описание деталей/расшифровки ошибки +// Возвращаемое значение: +// Структура - Детали ошибки: +// * ОшибкаУтверждения - Булево - Признак, это ошибка проверки утверждения +// * ПроверяемоеЗначение - Произвольный - Фактическое значение +// * ОжидаемоеЗначение - Произвольный - Ожидаемое значение +// * Сообщение - Строка +// * ДополнительныеДанные - Массив из Произвольный +// * Пояснения - Массив из Произвольный +Функция ОписаниеКонтекстаОшибки() + + Описание = Новый Структура("ПроверяемоеЗначение, ОжидаемоеЗначение"); + Описание.Вставить("ОшибкаУтверждения", Ложь); + Описание.Вставить("Сообщение", ""); + Описание.Вставить("ДополнительныеДанные", Новый Массив()); + Описание.Вставить("Пояснения", Новый Массив()); + + //@skip-check constructor-function-return-section + Возврат Описание; + +КонецФункции + +Функция ИмяКонтекстаОшибки() + + Возврат "ДанныеОшибки"; + +КонецФункции + +Функция ИмяКонтекстаДеталиОшибки() + + Возврат "ДеталиОшибки"; + +КонецФункции + +#КонецОбласти + +#Область КонструкторыОписанийОшибки + +Функция ДанныеОшибки(Ошибка, Знач Сообщение, ТипОшибки) + +#Если Сервер Тогда + Детали = КонтекстДеталиОшибки(Истина); +#Иначе + ДеталиСервер = КонтекстДеталиОшибки(Истина); + ДеталиКлиент = КонтекстДеталиОшибки(); + + Если ЗначениеЗаполнено(ДеталиКлиент) И ЗначениеЗаполнено(ДеталиСервер) Тогда + ЮТКоллекции.ДополнитьМассив(ДеталиСервер, ДеталиКлиент); + Детали = ДеталиСервер; + ИначеЕсли ЗначениеЗаполнено(ДеталиКлиент) Тогда + Детали = ДеталиКлиент; + ИначеЕсли ЗначениеЗаполнено(ДеталиСервер) Тогда + Детали = ДеталиСервер; + Иначе + Детали = Неопределено; + КонецЕсли; +#КонецЕсли + + Если ЗначениеЗаполнено(Детали) Тогда + ЮТКонтекстСлужебный.УстановитьЗначениеКонтекста(ИмяКонтекстаДеталиОшибки(), Неопределено); + + Детали.Добавить(Сообщение); + Сообщение = СтрСоединить(Детали, Символы.ПС); + КонецЕсли; + + ДанныеОшибки = ЮТФабрикаСлужебный.ОписаниеВозникшейОшибки(ТипОшибки + ": " + Сообщение); + + Если Ошибка <> Неопределено Тогда + ДанныеОшибки.Стек = СтекОшибки(Ошибка); + КонецЕсли; + ДанныеОшибки.ТипОшибки = ТипОшибки; + + ДобавитьСообщенияПользователю(); + ДобавитьЛогТеста(ДанныеОшибки); + + Возврат ДанныеОшибки; + +КонецФункции + +Функция ДанныеОшибкиУтверждений(Ошибка) + + Описание = ИзвлечьТекстОшибки(Ошибка, ПрефиксОшибкиУтверждений()); + + ДанныеОшибки = ЮТФабрикаСлужебный.ОписаниеОшибкиСравнения(Описание); + ДанныеОшибки.Стек = СтекОшибки(Ошибка); + + ДобавитьСообщенияПользователю(); + ДобавитьЛогТеста(ДанныеОшибки); + + СтруктураОшибки = КонтекстОшибки(); + + Если СтруктураОшибки <> Неопределено И СтруктураОшибки.ОшибкаУтверждения Тогда + ДанныеОшибки.ПроверяемоеЗначение = СтруктураОшибки.ПроверяемоеЗначение; + ДанныеОшибки.ОжидаемоеЗначение = СтруктураОшибки.ОжидаемоеЗначение; + КонецЕсли; + + Возврат ДанныеОшибки; + +КонецФункции + +Функция ДанныеОшибкиПропуска(Ошибка) + + Описание = ИзвлечьТекстОшибки(Ошибка, ПрефиксОшибкиПропуска()); + + ДанныеОшибки = ЮТФабрикаСлужебный.ОписаниеОшибкиПропуска(Описание); + + ДобавитьСообщенияПользователю(); + ДобавитьЛогТеста(ДанныеОшибки); + + Возврат ДанныеОшибки; + +КонецФункции + +Процедура ДобавитьЛогТеста(ДанныеОшибки) + + Лог = ЮТЛогИсполненияТестаСлужебный.Записи(); + Если Лог <> Неопределено Тогда + ЮТКоллекции.ДополнитьМассив(ДанныеОшибки.Лог, Лог); + КонецЕсли; + +КонецПроцедуры + +Функция СтекОшибки(Ошибка) + + Если ТипЗнч(Ошибка) = Тип("ИнформацияОбОшибке") Тогда + Возврат ПодробноеПредставлениеОшибки(Ошибка); + Иначе + Возврат Неопределено; + КонецЕсли; + +КонецФункции + +Функция ИзвлечьТекстОшибки(Ошибка, Префикс) + + ДлинаПрефикса = СтрДлина(Префикс); + + Описание = Сред(Ошибка.Описание, ДлинаПрефикса + 1); + Описание = СокрЛП(Описание); + + Если СтрНачинаетсяС(Описание, "<") И СтрЗаканчиваетсяНа(Описание, ">") Тогда + Описание = Сред(Описание, 2, СтрДлина(Описание) - 2); + КонецЕсли; + + Возврат Описание; + +КонецФункции + +#КонецОбласти + +Функция МодулиУтверждений() + + Возврат ЮТКоллекции.ЗначениеВМассиве("ЮТУтверждения"); + +КонецФункции + +Процедура СообщитьОбОшибке(Ошибка, Описание) + + ЮТОбщий.СообщитьПользователю(ПредставлениеОшибки(Описание, Ошибка)); + +КонецПроцедуры + +Функция ИнформациюОбОшибкеВСтроку(Ошибка, НомерПричины = 0) + + ТекстОшибки = ""; + + Если Ошибка = Неопределено Тогда + + ТекстОшибки = "Неизвестная ошибка."; + + ИначеЕсли ТипЗнч(Ошибка) = Тип("Строка") Тогда + + ТекстОшибки = Ошибка; + + ИначеЕсли ЭтоОшибкаСлужебногоМодуля(Ошибка) Тогда + + Если Ошибка.Причина = Неопределено Тогда + + ТекстОшибки = Ошибка.Описание; + + Иначе + + ТекстОшибки = ИнформациюОбОшибкеВСтроку(Ошибка.Причина, НомерПричины); + + КонецЕсли; + + Иначе + + Если НЕ ПустаяСтрока(Ошибка.ИмяМодуля) Тогда + + ТекстОшибки = ТекстОшибки + "{" + + Ошибка.ИмяМодуля + "(" + + Ошибка.НомерСтроки + ")}: "; + + КонецЕсли; + + ТекстОшибки = ТекстОшибки + Ошибка.Описание + ?(ПустаяСтрока(Ошибка.ИсходнаяСтрока), "", " + |" + Ошибка.ИсходнаяСтрока); + + Если Ошибка.Причина <> Неопределено Тогда + + ТекстОшибки = ТекстОшибки + " + | + |ПРИЧИНА №" + Формат(НомерПричины + 1, "ЧГ=0") + " + |" + ИнформациюОбОшибкеВСтроку(Ошибка.Причина, НомерПричины + 1); + + КонецЕсли; + + КонецЕсли; + + Возврат ТекстОшибки; + +КонецФункции + +Функция ЭтоОшибкаСлужебногоМодуля(Ошибка) + + Если НЕ ЗначениеЗаполнено(Ошибка.ИмяМодуля) Тогда + Возврат Ложь; + КонецЕсли; + + Для Каждого ИмяМодуля Из МодулиУтверждений() Цикл + Если СтрНайти(Ошибка.ИмяМодуля, ИмяМодуля) > 0 Тогда + Возврат Истина; + КонецЕсли; + КонецЦикла; + + Возврат Ложь; + +КонецФункции + +Процедура ДобавитьСообщенияПользователю() + +#Если Сервер ИЛИ ТолстыйКлиентОбычноеПриложение ИЛИ ТолстыйКлиентУправляемоеПриложение Тогда + Для Каждого Сообщение Из ПолучитьСообщенияПользователю(Истина) Цикл + ЮТест.ДобавитьСообщение(Сообщение.Текст); + КонецЦикла; +#КонецЕсли + +КонецПроцедуры + +Процедура ВызватьОшибкуИсполнения(Знач ИнформацияОбОшибке, ОписаниеПроверки) + + ТекстОшибки = ИнформациюОбОшибкеВСтроку(ИнформацияОбОшибке); + СообщениеОбОшибке = СообщениеОбОшибке(ТекстОшибки, ПрефиксОшибкиВыполнения(), ОписаниеПроверки); + ВызватьИсключение СообщениеОбОшибке; + +КонецПроцедуры + +Функция СообщениеОбОшибке(ТекстОшибки, ПрефиксТипаОшибки, ОписаниеПроверки = Неопределено) + + СообщениеОбОшибке = ДобавитьОписания(ТекстОшибки, ОписаниеПроверки); + + Возврат СтрШаблон("%1 <%2>", ПрефиксТипаОшибки, СообщениеОбОшибке); + +КонецФункции + +Функция ТекстыОшибокВызоваМетода(ИмяМетода) + + Тексты = Новый Структура("МетодНеОбнаружен, МногоПараметров, МалоПараметров"); + + Если ЮТЛокальСлужебный.ЭтоАнглийскаяЛокальПлатформы() Тогда + Тексты.МетодНеОбнаружен = СтрШаблон("Object method not found (%1)", ИмяМетода); + Тексты.МногоПараметров = "Too many actual parameters"; + Тексты.МалоПараметров = "Not enough actual parameters"; + Иначе + Тексты.МетодНеОбнаружен = СтрШаблон("Метод объекта не обнаружен (%1)", ИмяМетода); + Тексты.МногоПараметров = "Слишком много фактических параметров"; + Тексты.МалоПараметров = "Недостаточно фактических параметров"; + КонецЕсли; + + Возврат Тексты; + +КонецФункции + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТСлужебныйПовторногоИспользования.xml b/src/cfe/YAXUnit/CommonModules/ЮТСлужебныйПовторногоИспользования.xml new file mode 100644 index 0000000..a925aed --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТСлужебныйПовторногоИспользования.xml @@ -0,0 +1,23 @@ + + + + + ЮТСлужебныйПовторногоИспользования + + + ru + Повторного использования + + + + false + true + true + false + true + false + false + DuringSession + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТСлужебныйПовторногоИспользования/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТСлужебныйПовторногоИспользования/Ext/Module.bsl new file mode 100644 index 0000000..c6ee8f9 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТСлужебныйПовторногоИспользования/Ext/Module.bsl @@ -0,0 +1,94 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область СлужебныйПрограммныйИнтерфейс + +Функция АдресСерверногоКонтекста() Экспорт + + Возврат ЮТКонтекстСлужебныйВызовСервера.АдресСерверногоКонтекста(Ложь); + +КонецФункции + +Функция МетодМодуляСуществует(ИмяМодуля, ИмяМетода) Экспорт + + Возврат ЮТМетодыСлужебный.МетодМодуляСуществует(ИмяМодуля, ИмяМетода, Ложь); + +КонецФункции + +Функция ПараметрыТиповОшибок() Экспорт + + Возврат ЮТФабрикаСлужебный.ПараметрыТиповОшибок(Ложь); + +КонецФункции + +Функция ОписаниеТиповЛюбаяСсылка() Экспорт + + Возврат ЮТОбщийСлужебныйВызовСервера.ОписаниеТиповЛюбаяСсылка(); + +КонецФункции + +Функция ПодключитьКомпоненту(ИмяМакета, ИмяКомпоненты) Экспорт + + Возврат ЮТКомпоненты.ПодключитьКомпоненту(ИмяМакета, ИмяКомпоненты, Ложь); + +КонецФункции + +Функция СоздатьКомпоненту(ОписаниеКомпоненты) Экспорт + + Возврат ЮТКомпоненты.СоздатьКомпоненту(ОписаниеКомпоненты, Ложь); + +КонецФункции + +Функция ПримитивныеТипы() Экспорт + + Типы = Новый Массив(); + Типы.Добавить(Тип("Строка")); + Типы.Добавить(Тип("Число")); + Типы.Добавить(Тип("Дата")); + Типы.Добавить(Тип("Булево")); + Типы.Добавить(Тип("УникальныйИдентификатор")); + + Возврат Новый ФиксированныйМассив(Типы); + +КонецФункции + +Функция МножителиИнтервалов() Экспорт + + СекундВМинуте = 60; + СекундВЧасе = 60 * СекундВМинуте; + СекундВДне = СекундВЧасе * 24; + + Множители = Новый Структура; + Множители.Вставить("секунда", 1); + Множители.Вставить("секунды", 1); + Множители.Вставить("секунд", 1); + Множители.Вставить("минута", СекундВМинуте); + Множители.Вставить("минуты", СекундВМинуте); + Множители.Вставить("минут", СекундВМинуте); + Множители.Вставить("час", СекундВЧасе); + Множители.Вставить("часа", СекундВЧасе); + Множители.Вставить("часов", СекундВЧасе); + Множители.Вставить("день", СекундВДне); + Множители.Вставить("дня", СекундВДне); + Множители.Вставить("дней", СекундВДне); + + Возврат Множители; + +КонецФункции + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТСобытияСлужебный.xml b/src/cfe/YAXUnit/CommonModules/ЮТСобытияСлужебный.xml new file mode 100644 index 0000000..c4d2b0d --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТСобытияСлужебный.xml @@ -0,0 +1,23 @@ + + + + + ЮТСобытияСлужебный + + + ru + Генератор событий + + + + false + true + true + false + true + false + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТСобытияСлужебный/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТСобытияСлужебный/Ext/Module.bsl new file mode 100644 index 0000000..bb506ba --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТСобытияСлужебный/Ext/Module.bsl @@ -0,0 +1,364 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область СлужебныйПрограммныйИнтерфейс + +Процедура Инициализация(ПараметрыЗапуска) Экспорт + + Параметры = ЮТКоллекции.ЗначениеВМассиве(ПараметрыЗапуска); + ВызватьОбработчикРасширения("Инициализация", Параметры); + +КонецПроцедуры + +#Область СобытияИсполненияТестов + +// Обработчик события "ПередВсемиТестамиМодуля" +// +// Параметры: +// ТестовыйМодуль - см. ЮТФабрикаСлужебный.ОписаниеТестовогоМодуля +Процедура ПередВсемиТестамиМодуля(ТестовыйМодуль) Экспорт + + УстановитьКонтекстИсполнения(ТестовыйМодуль); + ЮТКонтекстСлужебный.УстановитьКонтекстМодуля(); + + ОписаниеСобытия = ЮТФабрикаСлужебный.ОписаниеСобытияИсполненияТестов(ТестовыйМодуль); + ВызватьОбработкуСобытия("ПередВсемиТестами", ОписаниеСобытия); + +КонецПроцедуры + +// Обработчик события "ПередТестовымНабором" +// +// Параметры: +// ТестовыйМодуль - см. ЮТФабрикаСлужебный.ОписаниеТестовогоМодуля +// Набор - см. ЮТФабрикаСлужебный.ОписаниеИсполняемогоНабораТестов +Процедура ПередТестовымНабором(ТестовыйМодуль, Набор) Экспорт + + УстановитьКонтекстИсполнения(ТестовыйМодуль, Набор); + ЮТКонтекстСлужебный.УстановитьКонтекстНабораТестов(); + + ОписаниеСобытия = ЮТФабрикаСлужебный.ОписаниеСобытияИсполненияТестов(ТестовыйМодуль, Набор); + ВызватьОбработкуСобытия("ПередТестовымНабором", ОписаниеСобытия); + +КонецПроцедуры + +// Обработчик события "ПередКаждымТестом" +// +// Параметры: +// ТестовыйМодуль - см. ЮТФабрикаСлужебный.ОписаниеТестовогоМодуля +// Набор - см. ЮТФабрикаСлужебный.ОписаниеИсполняемогоНабораТестов +// Тест - см. ЮТФабрикаСлужебный.ОписаниеИсполняемогоТеста +Процедура ПередКаждымТестом(ТестовыйМодуль, Набор, Тест) Экспорт + + // Установка контекста исполнения вызывается в см. ЮТИсполнительСлужебныйКлиентСервер.ПередКаждымТестом + ЮТКонтекстСлужебный.УстановитьКонтекстТеста(); + + ОписаниеСобытия = ЮТФабрикаСлужебный.ОписаниеСобытияИсполненияТестов(ТестовыйМодуль, Набор, Тест); + + #Если Сервер ИЛИ ТолстыйКлиентОбычноеПриложение ИЛИ ТолстыйКлиентУправляемоеПриложение Тогда + ПолучитьСообщенияПользователю(Истина); + #КонецЕсли + + ВызватьОбработкуСобытий(ЮТКоллекции.ЗначениеВМассиве("ПередКаждымТестом", "ПередТестом"), ОписаниеСобытия); + +КонецПроцедуры + +// Обработчик события "ПослеКаждогоТеста" +// +// Параметры: +// ТестовыйМодуль - см. ЮТФабрикаСлужебный.ОписаниеТестовогоМодуля +// Набор - см. ЮТФабрикаСлужебный.ОписаниеИсполняемогоНабораТестов +// Тест - см. ЮТФабрикаСлужебный.ОписаниеИсполняемогоТеста +Процедура ПослеКаждогоТеста(ТестовыйМодуль, Набор, Тест) Экспорт + + ОписаниеСобытия = ЮТФабрикаСлужебный.ОписаниеСобытияИсполненияТестов(ТестовыйМодуль, Набор, Тест); + + ВызватьОбработкуСобытий(ЮТКоллекции.ЗначениеВМассиве("ПослеТеста", "ПослеКаждогоТеста"), ОписаниеСобытия); + + УстановитьКонтекстИсполнения(ТестовыйМодуль, Набор); + +КонецПроцедуры + +// Обработчик события "ПослеТестовогоНабора" +// +// Параметры: +// ТестовыйМодуль - см. ЮТФабрикаСлужебный.ОписаниеТестовогоМодуля +// Набор - см. ЮТФабрикаСлужебный.ОписаниеИсполняемогоНабораТестов +Процедура ПослеТестовогоНабора(ТестовыйМодуль, Набор) Экспорт + + ОписаниеСобытия = ЮТФабрикаСлужебный.ОписаниеСобытияИсполненияТестов(ТестовыйМодуль, Набор); + ВызватьОбработкуСобытия("ПослеТестовогоНабора", ОписаниеСобытия); + + УстановитьКонтекстИсполнения(ТестовыйМодуль); + +КонецПроцедуры + +// Обработчик события "ПослеВсехТестовМодуля" +// +// Параметры: +// ТестовыйМодуль - см. ЮТФабрикаСлужебный.ОписаниеТестовогоМодуля +Процедура ПослеВсехТестовМодуля(ТестовыйМодуль) Экспорт + + ОписаниеСобытия = ЮТФабрикаСлужебный.ОписаниеСобытияИсполненияТестов(ТестовыйМодуль); + ВызватьОбработкуСобытия("ПослеВсехТестов", ОписаниеСобытия); + + УстановитьКонтекстИсполнения(); + +КонецПроцедуры + +// Перед выполнением тестов. +// +// Параметры: +// ИсполняемыеМодули - Массив из см. ЮТФабрикаСлужебный.ОписаниеИсполняемогоТестовогоМодуля +Процедура ПередВыполнениемТестов(ИсполняемыеМодули) Экспорт + + Параметры = ЮТКоллекции.ЗначениеВМассиве(ИсполняемыеМодули); + ВызватьОбработчикРасширения("ПередВыполнениемТестов", Параметры); + +КонецПроцедуры + +// После выполнения тестов. +// +// Параметры: +// РезультатТестирования - Массив из см. ЮТФабрикаСлужебный.ОписаниеИсполняемогоТестовогоМодуля +Процедура ПослеВыполненияТестов(РезультатТестирования) Экспорт + + Параметры = ЮТКоллекции.ЗначениеВМассиве(РезультатТестирования); + ВызватьОбработчикРасширения("ПослеВыполненияТестов", Параметры); + +КонецПроцедуры + +#КонецОбласти + +#Область СобытияЗагрузкиТестов + +// Обработка события "ПередЧтениеСценариев" +Процедура ПередЧтениеСценариев() Экспорт + + Параметры = Новый Массив(); + ВызватьОбработчикРасширения("ПередЧтениеСценариев", Параметры); + +КонецПроцедуры + +// Обработчик события "ПередЧтениемСценариевМодуля" +// Позволяет настроить базовые параметры перед чтением настроек тестов модуля +// Параметры: +// МетаданныеМодуля - см. ЮТФабрикаСлужебный.ОписаниеМодуля +Процедура ПередЧтениемСценариевМодуля(МетаданныеМодуля) Экспорт + + Параметры = ЮТКоллекции.ЗначениеВМассиве(МетаданныеМодуля); + ВызватьОбработчикРасширения("ПередЧтениемСценариевМодуля", Параметры); + +КонецПроцедуры + +// После чтения сценариев модуля. +// Позволяет настроить/обработать параметры загруженных настроек тестов модуля +// Параметры: +// МетаданныеМодуля - см. ЮТФабрикаСлужебный.ОписаниеМодуля +// ИсполняемыеСценарии - см. ЮТТесты.СценарииМодуля +Процедура ПослеЧтенияСценариевМодуля(МетаданныеМодуля, ИсполняемыеСценарии) Экспорт + + Параметры = ЮТКоллекции.ЗначениеВМассиве(МетаданныеМодуля, ИсполняемыеСценарии); + ВызватьОбработчикРасширения("ПослеЧтенияСценариевМодуля", Параметры); + +КонецПроцедуры + +// Обработка события "ПослеЧтенияСценариев" +// Параметры: +// Сценарии - Массив из см. ЮТФабрикаСлужебный.ОписаниеТестовогоМодуля - Набор описаний тестовых модулей, которые содержат информацию о запускаемых тестах +Процедура ПослеЧтенияСценариев(Сценарии) Экспорт + + Параметры = ЮТКоллекции.ЗначениеВМассиве(Сценарии); + ВызватьОбработчикРасширения("ПослеЧтенияСценариев", Параметры); + +КонецПроцедуры + +// Обработка события "ПослеФормированияИсполняемыхНаборовТестов" +// Параметры: +// ИсполняемыеТестовыеМодули - Массив из см. ЮТФабрикаСлужебный.ОписаниеИсполняемогоТестовогоМодуля - Набор исполняемых наборов +Процедура ПослеФормированияИсполняемыхНаборовТестов(ИсполняемыеТестовыеМодули) Экспорт + + Параметры = ЮТКоллекции.ЗначениеВМассиве(ИсполняемыеТестовыеМодули); + ВызватьОбработчикРасширения("ПослеФормированияИсполняемыхНаборовТестов", Параметры); + +КонецПроцедуры + +#КонецОбласти + +#КонецОбласти + +#Область СлужебныеПроцедурыИФункции + +Процедура УстановитьКонтекстИсполнения(ТестовыйМодуль = Неопределено, Набор = Неопределено, Тест = Неопределено) Экспорт + + Уровни = ЮТФабрика.УровниИсполнения(); + КонтекстИсполнения = ЮТКонтекстСлужебный.КонтекстИсполнения(); + + КонтекстИсполнения.Модуль = ТестовыйМодуль; + КонтекстИсполнения.Набор = Набор; + КонтекстИсполнения.Тест = Тест; + + Если Тест <> Неопределено Тогда + КонтекстИсполнения.Уровень = Уровни.Тест; + ИначеЕсли Набор <> Неопределено Тогда + КонтекстИсполнения.Уровень = Уровни.НаборТестов; + ИначеЕсли ТестовыйМодуль <> Неопределено Тогда + КонтекстИсполнения.Уровень = Уровни.Модуль; + Иначе + КонтекстИсполнения.Уровень = Неопределено; + КонецЕсли; + +КонецПроцедуры + +Процедура ВызватьОбработкуСобытий(События, ОписаниеСобытия) + + Для ы = 0 По События.ВГраница() Цикл + ИмяСобытия = События[ы]; + ПропуститьОбработчикТестовогоМодуля = (ы > 0 И ОбработчикСобытияПереопределен(ИмяСобытия)); + Если ПропуститьОбработчикТестовогоМодуля Тогда + + Параметры = ЮТКоллекции.ЗначениеВМассиве(ОписаниеСобытия); + Ошибки = ВызватьОбработчикРасширения(ИмяСобытия, Параметры); + ЗарегистрироватьОшибкиСобытияИсполнения(ИмяСобытия, ОписаниеСобытия, Ошибки); + + Иначе + + ВызватьОбработкуСобытия(ИмяСобытия, ОписаниеСобытия); + + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +Процедура ВызватьОбработкуСобытия(ИмяСобытия, ОписаниеСобытия) + + Параметры = ЮТКоллекции.ЗначениеВМассиве(ОписаниеСобытия); + + Если ЭтоСобытиеПеред(ИмяСобытия) Тогда + Ошибки = ВызватьОбработчикРасширения(ИмяСобытия, Параметры); + ВызватьОбработчикТестовогоМодуля(ИмяСобытия, ОписаниеСобытия); + Иначе + ВызватьОбработчикТестовогоМодуля(ИмяСобытия, ОписаниеСобытия); + Ошибки = ВызватьОбработчикРасширения(ИмяСобытия, Параметры); + КонецЕсли; + + ЗарегистрироватьОшибкиСобытияИсполнения(ИмяСобытия, ОписаниеСобытия, Ошибки); + +КонецПроцедуры + +Функция ВызватьОбработчикРасширения(ИмяСобытия, ПараметрыСобытия) + + Ошибки = Новый Массив(); + + Для Каждого ИмяМодуля Из ЮТРасширенияСлужебный.ОбработчикиСобытий() Цикл + + Если ЮТМетодыСлужебный.МетодМодуляСуществует(ИмяМодуля, ИмяСобытия) Тогда + ПолноеИмяМетода = СтрШаблон("%1.%2", ИмяМодуля, ИмяСобытия); + Ошибка = ЮТМетодыСлужебный.ВыполнитьМетод(ПолноеИмяМетода, ПараметрыСобытия); + + Если Ошибка <> Неопределено Тогда + Ошибки.Добавить(Ошибка); + КонецЕсли; + КонецЕсли; + + КонецЦикла; + + Возврат Ошибки; + +КонецФункции + +// Вызвать обработчик модуля. +// +// Параметры: +// ИмяСобытия - Строка - Имя вызываемого метода обработки события +// ОписаниеСобытия - см. ЮТФабрикаСлужебный.ОписаниеСобытияИсполненияТестов +// +Процедура ВызватьОбработчикТестовогоМодуля(Знач ИмяСобытия, ОписаниеСобытия) + + ОбработчикСобытияПереопределен = ОбработчикСобытияПереопределен(ИмяСобытия); + Если ОбработчикСобытияПереопределен Тогда + ИмяСобытия = ПереопределенноеИмяСобытия(ИмяСобытия); + КонецЕсли; + + ИмяМодуля = ОписаниеСобытия.Модуль.МетаданныеМодуля.Имя; + + ЧастиКоманды = СтрРазделить(ИмяСобытия, "."); + Если ЧастиКоманды.Количество() = 2 Тогда + ИмяМодуля = ЧастиКоманды[0]; + ИмяСобытия = ЧастиКоманды[1]; + КонецЕсли; + + Ошибки = Новый Массив(); + Команда = СтрШаблон("%1.%2()", ИмяМодуля, ИмяСобытия); + Если ЮТМетодыСлужебный.МетодМодуляСуществует(ИмяМодуля, ИмяСобытия) Тогда + + Ошибка = ЮТМетодыСлужебный.ВыполнитьМетод(Команда); + + Если Ошибка <> Неопределено Тогда + Ошибки.Добавить(Ошибка); + КонецЕсли; + + ИначеЕсли ОбработчикСобытияПереопределен Тогда + + ТекстИсключения = СтрШаблон("Не найден обработчик тестового модуля %1", Команда); + ВызватьИсключение ТекстИсключения; + + КонецЕсли; + + ЗарегистрироватьОшибкиСобытияИсполнения(ИмяСобытия, ОписаниеСобытия, Ошибки); + +КонецПроцедуры + +Процедура ЗарегистрироватьОшибкиСобытияИсполнения(ИмяСобытия, ОписаниеСобытия, Ошибки) + + Для Каждого Ошибка Из Ошибки Цикл + ЮТРегистрацияОшибокСлужебный.ЗарегистрироватьОшибкуСобытияИсполнения(ИмяСобытия, ОписаниеСобытия, Ошибка); + КонецЦикла; + +КонецПроцедуры + +Функция ОбработчикСобытияПереопределен(ИмяСобытия) + + Возврат ЗначениеЗаполнено(ПереопределенноеИмяСобытия(ИмяСобытия)); + +КонецФункции + +Функция ПереопределенноеИмяСобытия(ИмяСобытия) + + Если ЭтоСобытиеПеред(ИмяСобытия) Тогда + Возврат ЮТНастройкиВыполнения.Перед(); + ИначеЕсли ЭтоСобытиеПосле(ИмяСобытия) Тогда + Возврат ЮТНастройкиВыполнения.После(); + Иначе + Возврат ""; + КонецЕсли; + +КонецФункции + +Функция ЭтоСобытиеПеред(ИмяСобытия) + + Возврат СтрНачинаетсяС(ИмяСобытия, "Перед"); + +КонецФункции + +Функция ЭтоСобытиеПосле(ИмяСобытия) + + Возврат СтрНачинаетсяС(ИмяСобытия, "После"); + +КонецФункции + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТСообщенияСлужебный.xml b/src/cfe/YAXUnit/CommonModules/ЮТСообщенияСлужебный.xml new file mode 100644 index 0000000..80d0987 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТСообщенияСлужебный.xml @@ -0,0 +1,23 @@ + + + + + ЮТСообщенияСлужебный + + + ru + Сообщения служебный + + + + false + true + true + false + true + false + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТСообщенияСлужебный/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТСообщенияСлужебный/Ext/Module.bsl new file mode 100644 index 0000000..0627502 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТСообщенияСлужебный/Ext/Module.bsl @@ -0,0 +1,127 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область СлужебныйПрограммныйИнтерфейс + +// Форматированный текст ошибки утверждения. +// +// Параметры: +// ОписаниеПроверки - см. ЮТФабрикаСлужебный.ОписаниеПроверки +// ТекстОжидания - Строка - Описание ожидания +// ОбъектПроверки - Строка - Объект проверки +// +// Возвращаемое значение: +// Строка - Форматированный текст ошибки утверждения +Функция ФорматированныйТекстОшибкиУтверждения(Знач ОписаниеПроверки, ТекстОжидания, ОбъектПроверки) Экспорт + + Если ЗначениеЗаполнено(ОписаниеПроверки.ОбъектПроверки.ИмяСвойства) Тогда + ВставкаСвойство = СтрШаблон(" содержит свойство `%1`, которое", ОписаниеПроверки.ОбъектПроверки.ИмяСвойства); + Иначе + ВставкаСвойство = ""; + КонецЕсли; + + Если ЗначениеЗаполнено(ОписаниеПроверки.ОбъектПроверки.Представление) Тогда + ПредставлениеЗначения = ОписаниеПроверки.ОбъектПроверки.Представление; + Иначе + ПредставлениеЗначения = ПредставлениеЗначения(ОписаниеПроверки.ОбъектПроверки.Значение); + КонецЕсли; + + // Заголовок сообщения + ТекстСообщения = ""; + // Тело сообщения + ТекстСообщения = СтрШаблон("ожидали, что %1 %2%3 %4, но это не так.", + ОбъектПроверки, + ПредставлениеЗначения, + ВставкаСвойство, + ТекстОжидания); + + Возврат ТекстСообщения; + +КонецФункции + +// Сообщение об ошибке события. +// +// Параметры: +// ИмяСобытия - Строка +// Ошибка - Строка - Текст ошибки +// - ИнформацияОбОшибке - ошибка выполнения +// +// Возвращаемое значение: +// Строка - Сообщение об ошибке события +Функция СообщениеОбОшибкеСобытия(ИмяСобытия, Ошибка) Экспорт + + ТипОшибки = ЮТФабрикаСлужебный.ТипыОшибок().ОшибкаОбработкиСобытия; + Возврат СтрШаблон("%1 '%2': %3", ТипОшибки, ИмяСобытия, КраткоеСообщениеОшибки(Ошибка)); + +КонецФункции + +Функция КраткоеСообщениеОшибки(Ошибка) Экспорт + + Если ЭтоИнформацияОбОшибке(Ошибка) Тогда + Возврат КраткоеПредставлениеОшибки(Ошибка); + Иначе + Возврат Ошибка; + КонецЕсли; + +КонецФункции + +// Формирует строковое представление значения. Для значений, преобразуемых в пустые строки, добавляет описание типа. +// +// Параметры: +// Значение - Произвольный - Значение +// +// Возвращаемое значение: +// Строка - Представление значения +Функция ПредставлениеЗначения(Значение) Экспорт + ЗначениеСтрокой = Строка(Значение); + ТипЗначения = ТипЗнч(Значение); + Если ПустаяСтрока(ЗначениеСтрокой) Тогда + Тип = Строка(ТипЗначения); + Возврат СтрШаблон("`<Пустое значение, Тип: %1>`", Тип); + Иначе + Возврат СтрШаблон("`%1`", ЗначениеСтрокой); + КонецЕсли; +КонецФункции + +// Производит замену в переданном шаблоне параметра на переданное значение. +// +// Параметры: +// ШаблонСтроки - Строка - Шаблон строки, в которую должен быть подставлен параметр. +// ЗначениеПараметра - Произвольный - Значение параметра, подставляемое в шаблон. +// +// Возвращаемое значение: +// Строка - Если шаблон строки содержит в тексте параметр `%1`, он будет заменен переданным значением, +// в противном случае, будет возвращен текст шаблона без изменений. +// +Функция ПодставитьПредставлениеЗначенияВШаблон(ШаблонСтроки, ЗначениеПараметра) Экспорт + + Возврат СтрЗаменить(ШаблонСтроки, "%1", ПредставлениеЗначения(ЗначениеПараметра)); + +КонецФункции + +#КонецОбласти + +#Область СлужебныеПроцедурыИФункции + +Функция ЭтоИнформацияОбОшибке(Ошибка) Экспорт + + Возврат ТипЗнч(Ошибка) = Тип("ИнформацияОбОшибке"); + +КонецФункции + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТСравнениеСлужебныйВызовСервера.xml b/src/cfe/YAXUnit/CommonModules/ЮТСравнениеСлужебныйВызовСервера.xml new file mode 100644 index 0000000..25ad10c --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТСравнениеСлужебныйВызовСервера.xml @@ -0,0 +1,23 @@ + + + + + ЮТСравнениеСлужебныйВызовСервера + + + ru + Сравнение сервер + + + + false + false + true + false + false + true + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТСравнениеСлужебныйВызовСервера/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТСравнениеСлужебныйВызовСервера/Ext/Module.bsl new file mode 100644 index 0000000..e1d2697 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТСравнениеСлужебныйВызовСервера/Ext/Module.bsl @@ -0,0 +1,119 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область СлужебныйПрограммныйИнтерфейс + +Функция ТаблицыРавны(Знач Данные1, Знач Данные2) Экспорт + + Если Данные1.Количество() <> Данные2.Количество() Тогда + Возврат Ложь; + КонецЕсли; + + Если Данные1.Колонки.Количество() <> Данные2.Колонки.Количество() Тогда + Возврат Ложь; + КонецЕсли; + + Для Каждого Колонка Из Данные1.Колонки Цикл + Если Данные2.Колонки.Найти(Колонка.Имя) = Неопределено Тогда + Возврат Ложь; + КонецЕсли; + + Индекс = Данные1.Количество() - 1; + Пока Индекс >= 0 Цикл + Если НЕ ЮТСравнениеСлужебныйКлиентСервер.ЗначенияРавны(Данные1[Индекс][Колонка.Имя], Данные2[Индекс][Колонка.Имя]) Тогда + Возврат Ложь; + КонецЕсли; + Индекс = Индекс - 1; + КонецЦикла; + КонецЦикла; + + Возврат Истина; + +КонецФункции + +Функция ТабличныеДокументыРавны(Знач ТабличныйДокумент1, Знач ТабличныйДокумент2) Экспорт + + Данные1 = ПолучитьТаблицуЗначенийИзТабличногоДокумента(ТабличныйДокумент1); + Данные2 = ПолучитьТаблицуЗначенийИзТабличногоДокумента(ТабличныйДокумент2); + + Возврат ТаблицыРавны(Данные1, Данные2); + +КонецФункции + +#КонецОбласти + +#Область СлужебныеПроцедурыИФункции + +// https://github.com/vanessa-opensource/add +// портирован из Functest +Функция ПолучитьТаблицуЗначенийИзТабличногоДокумента(ТабличныйДокумент, УчитыватьТолькоВидимыеКолонки = Ложь, УчитыватьТолькоВидимыеСтроки = Ложь) + + ТипТабличногоДокумента = ТипЗнч(ТабличныйДокумент); + Если ТипТабличногоДокумента <> Тип("ТабличныйДокумент") И ТипТабличногоДокумента <> Тип("ПолеТабличногоДокумента") Тогда + ВызватьИсключение "ПолучитьТаблицуЗначенийИзТабличногоДокумента: Требуется тип ТабличныйДокумент или ПолеТабличногоДокумента"; + КонецЕсли; + + Если УчитыватьТолькоВидимыеКолонки И УчитыватьТолькоВидимыеСтроки Тогда + ЮТОбщийСлужебныйВызовСервера.ТаблицаИзТабличногоДокумента(ТипТабличногоДокумента); + КонецЕсли; + + НомерПоследнейКолонки = ТабличныйДокумент.ШиринаТаблицы; + НомерПоследнейСтроки = ТабличныйДокумент.ВысотаТаблицы; + + НоваяТаблицаЗначений = Новый ТаблицаЗначений; + Колонки = НоваяТаблицаЗначений.Колонки; + ТипСтрока = Новый ОписаниеТипов("Строка"); + + // TODO При определении видимости не учитывается наличие нескольких форматов строк, сейчас видимоcть колонки определяется по формату первой строки + УчитываемыеКолонки = Новый Массив; + Для НомерКолонки = 1 По НомерПоследнейКолонки Цикл + ОбластьКолонки = ТабличныйДокумент.Область(0, НомерКолонки, 1, НомерКолонки); + + УчитыватьКолонку = Не УчитыватьТолькоВидимыеКолонки Или ОбластьКолонки.Видимость; + Если УчитыватьКолонку Тогда + УчитываемыеКолонки.Добавить(НомерКолонки); + ШиринаКолонки = ОбластьКолонки.ШиринаКолонки; + Если ШиринаКолонки <= 1 Тогда + ШиринаКолонки = 1; + КонецЕсли; + ИмяКолонки = "К" + Формат(Колонки.Количество() + 1, "ЧН=; ЧГ=0"); + Колонки.Добавить(ИмяКолонки, ТипСтрока, ИмяКолонки, ШиринаКолонки); + КонецЕсли; + КонецЦикла; + + ГраницаКолонок = УчитываемыеКолонки.ВГраница(); + Для НомерСтроки = 1 По НомерПоследнейСтроки Цикл + + Если УчитыватьТолькоВидимыеСтроки И Не ТабличныйДокумент.Область(НомерСтроки, , НомерСтроки).Видимость Тогда + Продолжить; + КонецЕсли; + + НоваяСтрока = НоваяТаблицаЗначений.Добавить(); + + Для Индекс = 0 По ГраницаКолонок Цикл + НомерКолонки = УчитываемыеКолонки[Индекс]; + Область = ТабличныйДокумент.Область(НомерСтроки, НомерКолонки, НомерСтроки, НомерКолонки); + НоваяСтрока[Индекс] = Область.Текст; + КонецЦикла; + КонецЦикла; + + Возврат НоваяТаблицаЗначений; + +КонецФункции + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТСравнениеСлужебныйКлиентСервер.xml b/src/cfe/YAXUnit/CommonModules/ЮТСравнениеСлужебныйКлиентСервер.xml new file mode 100644 index 0000000..491ffe2 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТСравнениеСлужебныйКлиентСервер.xml @@ -0,0 +1,23 @@ + + + + + ЮТСравнениеСлужебныйКлиентСервер + + + ru + Сравнение клиент сервер + + + + false + true + true + false + true + false + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТСравнениеСлужебныйКлиентСервер/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТСравнениеСлужебныйКлиентСервер/Ext/Module.bsl new file mode 100644 index 0000000..ff4999b --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТСравнениеСлужебныйКлиентСервер/Ext/Module.bsl @@ -0,0 +1,657 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область СлужебныйПрограммныйИнтерфейс + +// Сравнивает данные сложной структуры с учетом вложенности. +// +// Параметры: +// Данные1 - Структура +// - ФиксированнаяСтруктура +// - Соответствие из Произвольный +// - ФиксированноеСоответствие из Произвольный +// - Массив из Произвольный +// - ФиксированныйМассив из Произвольный +// - Строка +// - Число +// - Булево +// - ТаблицаЗначений +// - ХранилищеЗначения +// Данные2 - Произвольный - те же типы, что и для параметра Данные1. +// ПараметрыСравнения - Структура - Параметры проверки: +// * ГлубокийАнализ - Булево - Использовать сериализацию и прочие алгоритмы сравнения +// Возвращаемое значение: +// Булево - Истина, если совпадают. +// +Функция ЗначенияРавны(Данные1, Данные2, ПараметрыСравнения = Неопределено) Экспорт + + ТипЗначения = ТипЗнч(Данные1); + Если ТипЗначения <> ТипЗнч(Данные2) Тогда + Возврат Ложь; + КонецЕсли; + + Если Данные1 = Данные2 Тогда + Возврат Истина; + КонецЕсли; + + Результат = Неопределено; + + Если ЮТТипыДанныхСлужебный.ЭтоСтруктура(ТипЗначения) Тогда + + Результат = СтруктурыРавны(Данные1, Данные2); + + ИначеЕсли ЮТТипыДанныхСлужебный.ЭтоСоответствие(ТипЗначения) Тогда + + Результат = СоответствияРавны(Данные1, Данные2); + + ИначеЕсли ЮТТипыДанныхСлужебный.ЭтоМассива(ТипЗначения) Тогда + + Результат = МассивыРавны(Данные1, Данные2); + + ИначеЕсли ТипЗначения = Тип("ТабличныйДокумент") Тогда + + Результат = ЮТСравнениеСлужебныйВызовСервера.ТабличныеДокументыРавны(Данные1, Данные2); + + ИначеЕсли ЮТТипыДанныхСлужебный.ЭтоПримитивныйТип(ТипЗначения) ИЛИ ЮТТипыДанныхСлужебный.ЭтоСсылочныйТип(ТипЗначения) Тогда + // Возвращаем ложь, так как для этих типов должно сработать обычное равенство + Результат = Ложь; + КонецЕсли; // BSLLS:IfElseIfEndsWithElse-off + +#Если Сервер Тогда + Если ТипЗначения = Тип("ТаблицаЗначений") Тогда + + Результат = ЮТСравнениеСлужебныйВызовСервера.ТаблицыРавны(Данные1, Данные2); + + ИначеЕсли ТипЗначения = Тип("ХранилищеЗначения") Тогда + + Результат = ЗначенияРавны(Данные1.Получить(), Данные2.Получить()); + + КонецЕсли; // BSLLS:IfElseIfEndsWithElse-off +#КонецЕсли + + Если Результат = Неопределено И ПараметрыСравнения <> Неопределено И ЮТКоллекции.ЗначениеСтруктуры(ПараметрыСравнения, "ГлубокийАнализ", Ложь) Тогда + Результат = СравнитьПоЗначению(Данные1, Данные2); + КонецЕсли; + + Если Результат = Неопределено Тогда + Результат = Ложь; + КонецЕсли; + + Возврат Результат; + +КонецФункции + +Функция ПроверитьНеравенство(ПроверяемоеЗначение, ОжидаемоеЗначение, Больше = Ложь, Меньше = Ложь, Равно = Ложь) Экспорт + + Результат = Ложь; + + Если Больше Тогда + Результат = ПроверяемоеЗначение > ОжидаемоеЗначение; + КонецЕсли; + + Если Меньше Тогда + Результат = Результат ИЛИ ПроверяемоеЗначение < ОжидаемоеЗначение; + КонецЕсли; + + Если Равно Тогда + Результат = Результат ИЛИ ПроверяемоеЗначение = ОжидаемоеЗначение; + КонецЕсли; + + Возврат Результат; + +КонецФункции + +// Параметры проверки. +// +// Параметры: +// ВидСравнения - Строка +// ПроверяемоеЗначение - Произвольный +// ИмяСвойства - Строка +// ОжидаемоеЗначение - Произвольный +// Реверс - Булево +// +// Возвращаемое значение: +// Структура - Параметры проверки: +// * ОбъектПроверки - см. ЮТФабрикаСлужебный.ОписаниеПроверяемогоЗначения +// * ПрефиксОшибки - Строка, Неопределено - +// * ОписаниеПроверки - Строка, Неопределено - +// * ВидСравнения - Строка +// * ОжидаемоеЗначение - Произвольный, Неопределено - +// * Реверс - Булево +// * ТекстПроверяемоеЗначение - Строка +Функция ПараметрыПроверки(ВидСравнения, ПроверяемоеЗначение, ИмяСвойства, ОжидаемоеЗначение, Реверс = Ложь) Экспорт + + Параметры = ЮТФабрикаСлужебный.ОписаниеПроверки(ПроверяемоеЗначение); + Параметры.ОбъектПроверки.ИмяСвойства = ИмяСвойства; + Параметры.Вставить("ВидСравнения", ВидСравнения); + Параметры.Вставить("ОжидаемоеЗначение", ОжидаемоеЗначение); + Параметры.Вставить("Реверс", Реверс); + + Параметры.Вставить("ТекстПроверяемоеЗначение", "проверяемое значение"); + + Возврат Параметры; + +КонецФункции + +#КонецОбласти + +#Область СлужебныеПроцедурыИФункции + +#Область Сравнения + +Функция СтруктурыРавны(Данные1, Данные2) + + Если Данные1.Количество() <> Данные2.Количество() Тогда + Возврат Ложь; + КонецЕсли; + + Для Каждого КлючИЗначение Из Данные1 Цикл + СтароеЗначение = Неопределено; + + Если НЕ Данные2.Свойство(КлючИЗначение.Ключ, СтароеЗначение) + ИЛИ НЕ ЗначенияРавны(КлючИЗначение.Значение, СтароеЗначение) Тогда + Возврат Ложь; + КонецЕсли; + КонецЦикла; + + Возврат Истина; + +КонецФункции + +Функция СоответствияРавны(Данные1, Данные2) + + Если Данные1.Количество() <> Данные2.Количество() Тогда + Возврат Ложь; + КонецЕсли; + + КлючиНовогоСоответствия = Новый Соответствие; + + Для Каждого КлючИЗначение Из Данные1 Цикл + КлючиНовогоСоответствия.Вставить(КлючИЗначение.Ключ, Истина); + СтароеЗначение = Данные2.Получить(КлючИЗначение.Ключ); + + Если НЕ ЗначенияРавны(КлючИЗначение.Значение, СтароеЗначение) Тогда + Возврат Ложь; + КонецЕсли; + КонецЦикла; + + Для Каждого КлючИЗначение Из Данные2 Цикл + Если КлючиНовогоСоответствия[КлючИЗначение.Ключ] = Неопределено Тогда + Возврат Ложь; + КонецЕсли; + КонецЦикла; + + Возврат Истина; + +КонецФункции + +Функция МассивыРавны(Данные1, Данные2) + + Если Данные1.Количество() <> Данные2.Количество() Тогда + Возврат Ложь; + КонецЕсли; + + Для Индекс = 0 По Данные1.ВГраница() Цикл + Если НЕ ЗначенияРавны(Данные1[Индекс], Данные2[Индекс]) Тогда + Возврат Ложь; + КонецЕсли; + КонецЦикла; + + Возврат Истина; + +КонецФункции + +Функция ПроверитьТипЗначения(РезультатПроверки, + Значение, + Знач ОжидаемыйТип, + Описание = "ожидаемого значения", + ЕслиУстановлен = Ложь, + Суффикс = Неопределено) + + Если ЕслиУстановлен И Значение = Неопределено Тогда + Возврат Истина; + КонецЕсли; + + Соответствует = ЮТПроверкиСлужебный.ТипЗначенияСоответствует(Значение, ОжидаемыйТип); + + Если НЕ Соответствует Тогда + ТекстОшибки = СтрШаблон("Не верный тип %1 (`%2`), должен быть `%3`%4", + Описание, + ТипЗнч(Значение), + ОжидаемыйТип, + Суффикс); + ЮТРегистрацияОшибокСлужебный.ДобавитьОшибкуКРезультатуПроверки(РезультатПроверки, ТекстОшибки); + КонецЕсли; + + Возврат Соответствует; + +КонецФункции + +Функция СравнитьПоЗначению(Значение1, Значение2) + + Попытка + СтрокаСравнения1 = ЮТОбщий.СтрокаJSON(Значение1); + СтрокаСравнения2 = ЮТОбщий.СтрокаJSON(Значение2); + Возврат СтрокаСравнения1 = СтрокаСравнения2; + Исключение + Возврат Ложь; + КонецПопытки; + +КонецФункции + +#КонецОбласти + +Функция ЗначениеИмеетСвойство(Значение, Свойство) + + Результат = Ложь; + ТипЗначения = ТипЗнч(Значение); + + Если ЮТТипыДанныхСлужебный.ЭтоСтруктура(ТипЗначения) Тогда + + Результат = Значение.Свойство(Свойство); + + ИначеЕсли ЮТТипыДанныхСлужебный.ЭтоСоответствие(ТипЗначения) Тогда + + Для Каждого КлючЗначение Из Значение Цикл + + Если КлючЗначение.Ключ = Свойство И ТипЗнч(КлючЗначение.Ключ) = ТипЗнч(Свойство) Тогда + Результат = Истина; + Прервать; + КонецЕсли; + + КонецЦикла; + + ИначеЕсли ТипЗнч(Свойство) = Тип("Число") Тогда + + Если Свойство < 0 Тогда + Свойство = Значение.Количество() + Свойство; + КонецЕсли; + Результат = Свойство >= 0 И Значение.Количество() > Свойство; + + Иначе + + Результат = ЮТОбщий.ПеременнаяСодержитСвойство(Значение, Свойство); + + КонецЕсли; + + Возврат Результат; + +КонецФункции + +// Параметры проверки. +// +// Параметры: +// ПараметрыПроверки - см. ПараметрыПроверки +// +// Возвращаемое значение: +// Произвольный +Функция ПроверяемоеЗначение(ПараметрыПроверки) + + Если ПараметрыПроверки.ОбъектПроверки.ИмяСвойства <> Неопределено Тогда + Значение = ЮТОбщий.ЗначениеСвойства(ПараметрыПроверки.ОбъектПроверки.Значение, ПараметрыПроверки.ОбъектПроверки.ИмяСвойства); + Иначе + Значение = ПараметрыПроверки.ОбъектПроверки.Значение; + КонецЕсли; + + Возврат Значение; + +КонецФункции + +Функция ДлинаЗначения(ПроверяемоеЗначение) + + ТипПроверяемогоЗначения = ТипЗнч(ПроверяемоеЗначение); + + Если ТипПроверяемогоЗначения = Тип("Строка") ИЛИ ТипПроверяемогоЗначения = Тип("ФорматированнаяСтрока") Тогда + + ФактическаяДлина = СтрДлина(ПроверяемоеЗначение); + + Иначе + + Попытка + ФактическаяДлина = ПроверяемоеЗначение.Количество(); + Исключение + ФактическаяДлина = Неопределено; + КонецПопытки; + + КонецЕсли; + + Возврат ФактическаяДлина; + +КонецФункции + +Функция СоответствуетШаблону(ПроверяемаяСтрока, РегулярноеВыражение) + + РегулярныеВыражения = ЮТКомпоненты.РегулярныеВыражения(); + + Попытка + Результат = РегулярныеВыражения.Совпадает(Строка(ПроверяемаяСтрока), РегулярноеВыражение); + Исключение + ЮТРегистрацияОшибок.ДобавитьПояснениеОшибки("Ошибка проверки строки по шаблону " + РегулярноеВыражение); + ЮТРегистрацияОшибок.ДобавитьПояснениеОшибки(РегулярныеВыражения.ОписаниеОшибки); + ВызватьИсключение; + КонецПопытки; + + Возврат Результат; + +КонецФункции + +Функция НайтиЗначение(ПроверяемоеЗначение, ОжидаемоеЗначение) + + ТипПроверяемогоЗначения = ТипЗнч(ПроверяемоеЗначение); + + Если ТипПроверяемогоЗначения = Тип("Строка") Или ТипПроверяемогоЗначения = Тип("ФорматированнаяСтрока") Тогда + + ИскомоеЗначениеНайдено = СтрНайти(ПроверяемоеЗначение, ОжидаемоеЗначение) > 0; + + ИначеЕсли ЮТТипыДанныхСлужебный.ЭтоМассива(ТипПроверяемогоЗначения) Тогда + + Индекс = ПроверяемоеЗначение.Найти(ОжидаемоеЗначение); + ИскомоеЗначениеНайдено = Индекс <> Неопределено; + + ИначеЕсли ЮТТипыДанныхСлужебный.ЭтоКлючЗначение(ТипПроверяемогоЗначения) Тогда + + ИскомоеЗначениеНайдено = Ложь; + ТипОжидаемогоЗначения = ТипЗнч(ОжидаемоеЗначение); + + Для Каждого КлючЗначение Из ПроверяемоеЗначение Цикл + Если КлючЗначение.Значение = ОжидаемоеЗначение И ТипЗнч(КлючЗначение.Значение) = ТипОжидаемогоЗначения Тогда + ИскомоеЗначениеНайдено = Истина; + Прервать; + КонецЕсли; + КонецЦикла; + + ИначеЕсли ТипПроверяемогоЗначения = Тип("СписокЗначений") Тогда + + ИскомоеЗначениеНайдено = ПроверяемоеЗначение.НайтиПоЗначению(ОжидаемоеЗначение) <> Неопределено; + + ИначеЕсли ПроверяемоеЗначение <> Неопределено И ЮТМетодыСлужебный.МетодОбъектаСуществует(ПроверяемоеЗначение, "Найти") Тогда + + ИскомоеЗначениеНайдено = ПроверяемоеЗначение.Найти(ОжидаемоеЗначение) <> Неопределено; + + Иначе + + ИскомоеЗначениеНайдено = Неопределено; // Обрабатывается вызывающим методом + + КонецЕсли; + + Возврат ИскомоеЗначениеНайдено; + +КонецФункции + +#Область РеализацияПредикатор + +Процедура ПроверитьВыражениеПредиката(Значение, Выражение, СтатусПроверки, ПараметрыСообщенийОбОшибке, ПараметрыСравнения) Экспорт + + Попытка + ВызватьОбработчикПредиката(Значение, Выражение, СтатусПроверки, ПараметрыСообщенийОбОшибке, ПараметрыСравнения); + Исключение + ЮТРегистрацияОшибокСлужебный.ДобавитьОшибкуКРезультатуПроверки(СтатусПроверки, ИнформацияОбОшибке()); + КонецПопытки; + +КонецПроцедуры + +// Вычислить выражение предиката. +// +// Параметры: +// Значение - Произвольный - Значение +// Выражение - см. ЮТФабрика.ВыражениеПредиката +// СтатусПроверки - см. ЮТФабрикаСлужебный.ОписаниеРезультатаПроверки +// ПараметрыСообщенийОбОшибке - см. ПараметрыСообщенийОбОшибке +// ПараметрыСравнения - Неопределено +// - Структура - Параметры сравнения значений, для разных выражений испльзуются свои параметры +Процедура ВызватьОбработчикПредиката(Значение, Выражение, СтатусПроверки, ПараметрыСообщенийОбОшибке, ПараметрыСравнения) + +// BSLLS:CognitiveComplexity-off + ВидыСравнения = ЮТПредикаты.Выражения(); + + ПараметрыПроверки = ПараметрыПроверки(Выражение.ВидСравнения, Значение, Выражение.ИмяРеквизита, Выражение.Значение, Ложь); + + ПараметрыПроверки.ОписаниеПроверки = ПараметрыСообщенийОбОшибке.ОписаниеПроверки; + ПараметрыПроверки.ТекстПроверяемоеЗначение = ПараметрыСообщенийОбОшибке.ТекстПроверяемоеЗначение; + ПараметрыПроверки.ОбъектПроверки.Представление = ПараметрыСообщенийОбОшибке.ПредставлениеПроверяемогоЗначения; + + Если СтрНачинаетсяС(Выражение.ВидСравнения, "Не") И ВидыСравнения.Свойство(Сред(Выражение.ВидСравнения, 3)) Тогда + ПараметрыПроверки.Реверс = Истина; + ВидСравненияВыражения = Сред(Выражение.ВидСравнения, 3); + Иначе + ВидСравненияВыражения = Выражение.ВидСравнения; + КонецЕсли; + + Результат = Неопределено; + + ОжидаемоеЗначение = Выражение.Значение; + ПроверяемоеЗначение = ПроверяемоеЗначение(ПараметрыПроверки); + + Если ВидСравненияВыражения = ВидыСравнения.Равно Тогда + + Результат = ЗначенияРавны(ПроверяемоеЗначение, ОжидаемоеЗначение, ПараметрыСравнения); + + ИначеЕсли ВидСравненияВыражения = ВидыСравнения.Заполнено Тогда + + Результат = ЗначениеЗаполнено(ПроверяемоеЗначение); + + ИначеЕсли ВидСравненияВыражения = ВидыСравнения.Больше Тогда + + Результат = ПроверитьНеравенство(ПроверяемоеЗначение, ОжидаемоеЗначение, Истина); + + ИначеЕсли ВидСравненияВыражения = ВидыСравнения.БольшеРавно Тогда + + Результат = ПроверитьНеравенство(ПроверяемоеЗначение, ОжидаемоеЗначение, Истина, , Истина); + + ИначеЕсли ВидСравненияВыражения = ВидыСравнения.Меньше Тогда + + Результат = ПроверитьНеравенство(ПроверяемоеЗначение, ОжидаемоеЗначение, , Истина); + + ИначеЕсли ВидСравненияВыражения = ВидыСравнения.МеньшеРавно Тогда + + Результат = ПроверитьНеравенство(ПроверяемоеЗначение, ОжидаемоеЗначение, , Истина, Истина); + + ИначеЕсли ВидСравненияВыражения = ВидыСравнения.ИмеетТип Тогда + + ПроверитьТипПараметра(СтатусПроверки, ПроверяемоеЗначение, ОжидаемоеЗначение, ПараметрыПроверки); + + ИначеЕсли ВидСравненияВыражения = ВидыСравнения.ИмеетСвойство Тогда + + Результат = ПроверитьНаличиеСвойства(СтатусПроверки, ПроверяемоеЗначение, ОжидаемоеЗначение); + + ИначеЕсли ВидСравненияВыражения = ВидыСравнения.ИмеетДлину Тогда + + ПроверитьДлину(СтатусПроверки, ПроверяемоеЗначение, ОжидаемоеЗначение, ПараметрыПроверки); + + ИначеЕсли ВидСравненияВыражения = ВидыСравнения.Содержит Тогда + + Результат = ПроверитьСодержит(СтатусПроверки, ПроверяемоеЗначение, ОжидаемоеЗначение, ПараметрыПроверки); + + ИначеЕсли ВидСравненияВыражения = ВидыСравнения.СодержитСтрокуПоШаблону Тогда + + Результат = ПроверитьСоответствуетШаблону(СтатусПроверки, ПроверяемоеЗначение, ОжидаемоеЗначение, ПараметрыПроверки); + + ИначеЕсли ВидСравненияВыражения = ВидыСравнения.ВСписке Тогда + + Результат = ПроверитьВСписке(СтатусПроверки, ПроверяемоеЗначение, ОжидаемоеЗначение, ПараметрыПроверки); + + Иначе + + ВызватьИсключение СтрШаблон("Неизвестное выражение предиката `%1`", Выражение.ВидСравнения); + + КонецЕсли; +// BSLLS:CognitiveComplexity-on + + Если Результат = Неопределено Тогда + Возврат; + КонецЕсли; + + Если ПараметрыПроверки.Реверс Тогда + Результат = НЕ Результат; + КонецЕсли; + + ОбработатьРезультатСравнения(Результат, СтатусПроверки, ПараметрыПроверки, ПроверяемоеЗначение); + +КонецПроцедуры + +Процедура ОбработатьРезультатСравнения(Результат, РезультатПроверки, ПараметрыПроверки, ФактическоеЗначение) + + Если Результат Тогда + Возврат; + КонецЕсли; + + ШаблонСообщения = ЮТПредикатыСлужебныйКлиентСервер.ШаблонВыражения(ПараметрыПроверки.ВидСравнения); + Сообщение = ЮТСообщенияСлужебный.ПодставитьПредставлениеЗначенияВШаблон(ШаблонСообщения, ПараметрыПроверки.ОжидаемоеЗначение); + + ТекстОшибки = ЮТСообщенияСлужебный.ФорматированныйТекстОшибкиУтверждения(ПараметрыПроверки, Сообщение, ПараметрыПроверки.ТекстПроверяемоеЗначение); + ТекстОшибки = ЮТРегистрацияОшибокСлужебный.ДобавитьОписания(ТекстОшибки, ПараметрыПроверки); + + ЮТРегистрацияОшибокСлужебный.ДобавитьОшибкуСравненияКРезультатуПроверки(РезультатПроверки, + ТекстОшибки, + ФактическоеЗначение, + ПараметрыПроверки.ОжидаемоеЗначение); + +КонецПроцедуры + +Процедура ПроверитьТипПараметра(РезультатПроверки, ПроверяемоеЗначение, ОжидаемоеЗначение, ПараметрыПроверки) + + Если НЕ ПроверитьТипЗначения(РезультатПроверки, ОжидаемоеЗначение, Новый ОписаниеТипов("ОписаниеТипов, Тип, Строка")) Тогда + Возврат; + КонецЕсли; + + Результат = ЮТПроверкиСлужебный.ТипЗначенияСоответствует(ПроверяемоеЗначение, ПараметрыПроверки.ОжидаемоеЗначение); + + Если ПараметрыПроверки.Реверс Тогда + Результат = НЕ Результат; + КонецЕсли; + + ОбработатьРезультатСравнения(Результат, РезультатПроверки, ПараметрыПроверки, ТипЗнч(ПроверяемоеЗначение)); + +КонецПроцедуры + +Функция ПроверитьНаличиеСвойства(РезультатПроверки, ПроверяемоеЗначение, ОжидаемоеЗначение) + + Значение = ПроверяемоеЗначение; + + ПутьКСвойству = ЮТОбщий.ЧастиПути(ОжидаемоеЗначение); + + ПройденныйПуть = Новый Массив(); + + Для Каждого Часть Из ПутьКСвойству Цикл + + ПройденныйПуть.Добавить(Часть); + + Если ТипЗнч(Значение) = Тип("ХранилищеЗначения") Тогда +#Если ВебКлиент Или ТонкийКлиент Тогда + Значение = ЮТОбщийСлужебныйВызовСервера.ИзХранилищаЗначений(Значение); +#Иначе + Значение = Значение.Получить(); +#КонецЕсли + КонецЕсли; + + Попытка + ЕстьСвойство = ЗначениеИмеетСвойство(Значение, Часть); + Исключение + ЕстьСвойство = Ложь; + КонецПопытки; + + Если ЕстьСвойство Тогда + Значение = Значение[Часть]; + Иначе + Прервать; + КонецЕсли; + + КонецЦикла; + + Возврат ЕстьСвойство; + +КонецФункции + +Процедура ПроверитьДлину(РезультатПроверки, ПроверяемоеЗначение, ОжидаемоеЗначение, ПараметрыПроверки) + + Если НЕ ПроверитьТипЗначения(РезультатПроверки, ОжидаемоеЗначение, "Число") Тогда + Возврат; + КонецЕсли; + + ФактическаяДлина = ДлинаЗначения(ПроверяемоеЗначение); + + Если ФактическаяДлина = Неопределено Тогда + ТекстОшибки = СтрШаблон("тип проверяемого значения `%1` не обрабатывается утверждением", ТипЗнч(ПроверяемоеЗначение)); + ЮТРегистрацияОшибокСлужебный.ДобавитьОшибкуКРезультатуПроверки(РезультатПроверки, ТекстОшибки, ПараметрыПроверки); + Возврат; + КонецЕсли; + + Результат = ФактическаяДлина = ПараметрыПроверки.ОжидаемоеЗначение; + + Если ПараметрыПроверки.Реверс Тогда + Результат = НЕ Результат; + КонецЕсли; + + ОбработатьРезультатСравнения(Результат, РезультатПроверки, ПараметрыПроверки, ФактическаяДлина); + +КонецПроцедуры + +Функция ПроверитьСодержит(РезультатПроверки, ПроверяемоеЗначение, ОжидаемоеЗначение, ПараметрыПроверки) + + Результат = НайтиЗначение(ПроверяемоеЗначение, ОжидаемоеЗначение); + + Если Результат = Неопределено Тогда + ТекстОшибки = СтрШаблон("тип проверяемого значения `%1` не обрабатывается утверждением", ТипЗнч(ПроверяемоеЗначение)); + ЮТРегистрацияОшибокСлужебный.ДобавитьОшибкуКРезультатуПроверки(РезультатПроверки, ТекстОшибки, ПараметрыПроверки); + КонецЕсли; + + Возврат Результат; + +КонецФункции + +Функция ПроверитьСоответствуетШаблону(РезультатПроверки, ПроверяемоеЗначение, ОжидаемоеЗначение, ПараметрыПроверки) + + ТипыПараметровСоответствуют = ПроверитьТипЗначения(РезультатПроверки, ОжидаемоеЗначение, "Строка") + И ПроверитьТипЗначения(РезультатПроверки, ПроверяемоеЗначение, "Строка, ФорматированнаяСтрока", "проверяемого значения"); + + Если Не ТипыПараметровСоответствуют Тогда + Возврат Неопределено; + КонецЕсли; + + СоответствуетШаблону = СоответствуетШаблону(ПроверяемоеЗначение, ОжидаемоеЗначение); + + Если СоответствуетШаблону = Неопределено Тогда + ТекстОшибки = СтрШаблон("тип проверяемого значения `%1` не обрабатывается утверждением", ТипЗнч(ПроверяемоеЗначение)); + ЮТРегистрацияОшибокСлужебный.ДобавитьОшибкуКРезультатуПроверки(РезультатПроверки, ТекстОшибки, ПараметрыПроверки); + КонецЕсли; + + Возврат СоответствуетШаблону; + +КонецФункции + +Функция ПроверитьВСписке(РезультатПроверки, ПроверяемоеЗначение, ОжидаемоеЗначение, ПараметрыПроверки) + + ТипыПараметровСоответствуют = ПроверитьТипЗначения(РезультатПроверки, ОжидаемоеЗначение, "Массив, ФиксированныйМассив, СписокЗначений"); + + Если Не ТипыПараметровСоответствуют Тогда + Возврат Неопределено; + КонецЕсли; + + ТипСписка = ТипЗнч(ОжидаемоеЗначение); + + Если ЮТТипыДанныхСлужебный.ЭтоМассива(ТипСписка) Тогда + Возврат ОжидаемоеЗначение.Найти(ПроверяемоеЗначение) <> Неопределено; + Иначе + Возврат ОжидаемоеЗначение.НайтиПоЗначению(ПроверяемоеЗначение) <> Неопределено; + КонецЕсли; + +КонецФункции + +#КонецОбласти + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТСтроки.xml b/src/cfe/YAXUnit/CommonModules/ЮТСтроки.xml new file mode 100644 index 0000000..fa6a336 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТСтроки.xml @@ -0,0 +1,23 @@ + + + + + ЮТСтроки + + + ru + Строки + + + + false + true + true + false + true + false + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТСтроки/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТСтроки/Ext/Module.bsl new file mode 100644 index 0000000..33c7b5e --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТСтроки/Ext/Module.bsl @@ -0,0 +1,188 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область ПрограммныйИнтерфейс + +// Конкатенирует строки, разделяя их разделителем +// +// Параметры: +// ИсходнаяСтрока - Строка - Исходная строка +// ДополнительнаяСтрока - Строка - Добавляемая строка +// Разделитель - Строка - Строка разделитель, любой набор символов - разделитель между подстроками +// +// Возвращаемое значение: +// Строка - Результат конкатенации строк +// +Функция ДобавитьСтроку(ИсходнаяСтрока, ДополнительнаяСтрока, Разделитель = ";") Экспорт + + Если Не ПустаяСтрока(ДополнительнаяСтрока) Тогда + + Если Не ПустаяСтрока(ИсходнаяСтрока) Тогда + Возврат Строка(ИсходнаяСтрока) + Разделитель + Строка(ДополнительнаяСтрока); + Иначе + Возврат Строка(ДополнительнаяСтрока); + КонецЕсли; + + КонецЕсли; + + Возврат Строка(ИсходнаяСтрока); + +КонецФункции + +// Возвращает массив на основании строки. +// При этом: +// * отсекает незначащие символы, стоящие слева от первого значащего символа в строке, и пробелы, стоящие справа от последнего значащего символа в строке. +// * в отличии от `СтрРазделить` в качестве разделителля используется вся переданная строка, а не любой из символов входящий в нее. +// +// Параметры: +// Значение - Строка - преобразуемая строка +// Разделитель - Строка - строка-разделитель +// +// Возвращаемое значение: +// Массив Из Строка - массив строк +// +Функция РазделитьСтроку(Знач Значение, Разделитель = ";") Экспорт + + КодУниверсальногоРазделителя = 5855; + УниверсальныйРазделитель = Символ(КодУниверсальногоРазделителя); + МодифицированнаяСтрока = СтрЗаменить(Значение, Разделитель, УниверсальныйРазделитель); + + МассивСтрок = ?(МодифицированнаяСтрока = "", Новый Массив, СтрРазделить(МодифицированнаяСтрока, УниверсальныйРазделитель)); + + Для Индекс = 0 По МассивСтрок.ВГраница() Цикл + МассивСтрок[Индекс] = СокрЛП(МассивСтрок[Индекс]); + КонецЦикла; + + Возврат МассивСтрок; + +КонецФункции + +// Формирует строку из заданного количества повторяемых символов +// Параметры: +// Символ - Строка - Повторяемый символ +// Количество - Число - Количество повторений +// +// Возвращаемое значение: +// Строка - Строка повторяемых символов +Функция СтрокаСимволов(Символ, Количество) Экспорт + + Возврат СтрСоединить(Новый Массив(Количество + 1), Символ); + +КонецФункции + +// Строка с символами русского алфавита +// +// Параметры: +// НижнийРегистр - Булево - добавить символы в нижнем регистре +// ВерхнийРегистр - Булево - добавить символы в верхнем регистре +// +// Возвращаемое значение: +// Строка +Функция РусскиеБуквы(НижнийРегистр = Истина, ВерхнийРегистр = Ложь) Экспорт + + Возврат Буквы("абвгдеёжзийклмнопрстуфхцчшщъыьэюя", НижнийРегистр, ВерхнийРегистр); + +КонецФункции + +// Строка с символами английского алфавита +// +// Параметры: +// НижнийРегистр - Булево - добавить символы в нижнем регистре +// ВерхнийРегистр - Булево - добавить символы в верхнем регистре +// +// Возвращаемое значение: +// Строка +Функция АнглийскиеБуквы(НижнийРегистр = Истина, ВерхнийРегистр = Ложь) Экспорт + + Возврат Буквы("abcdefghijklmnopqrstuvwxyz", НижнийРегистр, ВерхнийРегистр); + +КонецФункции + +// Строка с числами +// +// Возвращаемое значение: +// Строка +Функция Цифры() Экспорт + + Возврат "1234567890"; + +КонецФункции + +// Выполняет сравнение версий +// +// Параметры: +// Версия1 - Строка +// Версия2 - Строка +// +// Возвращаемое значение: +// Число - Результат сравнения +// `-1` - Версия1 меньше Версия2 +// `0` - Версии равны +// `1` - Версия1 больше Версия2 +Функция СравнитьВерсии(Версия1, Версия2) Экспорт + + ЧастиВерсия1 = СтрРазделить(Версия1, "."); + ЧастиВерсия2 = СтрРазделить(Версия2, "."); + + КоличествоЧастейВерсия1 = ЧастиВерсия1.Количество(); + КоличествоЧастейВерсия2 = ЧастиВерсия2.Количество(); + + КоличествоЧастей = Макс(КоличествоЧастейВерсия1, КоличествоЧастейВерсия2); + + Для Инд = КоличествоЧастейВерсия1 По КоличествоЧастей - 1 Цикл + ЧастиВерсия1.Добавить("0"); + КонецЦикла; + + Для Инд = КоличествоЧастейВерсия2 По КоличествоЧастей - 1 Цикл + ЧастиВерсия2.Добавить("0"); + КонецЦикла; + + Результат = 0; + + Для Разряд = 0 По КоличествоЧастей - 1 Цикл + + Результат = Число(ЧастиВерсия1[Разряд]) - Число(ЧастиВерсия2[Разряд]); + Если Результат <> 0 Тогда + Прервать; + КонецЕсли; + + КонецЦикла; + + Возврат Макс(Мин(Результат, 1), -1); + +КонецФункции + +#КонецОбласти + +#Область СлужебныеПроцедурыИФункции + +Функция Буквы(Буквы, НижнийРегистр, ВерхнийРегистр) + + Если НижнийРегистр И ВерхнийРегистр Тогда + Возврат Буквы + ВРег(Буквы); + ИначеЕсли НижнийРегистр Тогда + Возврат Буквы; + ИначеЕсли ВерхнийРегистр Тогда + Возврат ВРег(Буквы); + Иначе + Возврат ""; + КонецЕсли; + +КонецФункции + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТТестовыеДанные.xml b/src/cfe/YAXUnit/CommonModules/ЮТТестовыеДанные.xml new file mode 100644 index 0000000..ff4e344 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТТестовыеДанные.xml @@ -0,0 +1,23 @@ + + + + + ЮТТестовыеДанные + + + ru + Тестовые данные + + + + false + true + true + false + true + false + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТТестовыеДанные/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТТестовыеДанные/Ext/Module.bsl new file mode 100644 index 0000000..f865bf8 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТТестовыеДанные/Ext/Module.bsl @@ -0,0 +1,881 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область ПрограммныйИнтерфейс + +// Создает новый элемент и возвращает его ссылку. +// +// Параметры: +// Менеджер - Произвольный - Менеджер справочника/ПВХ и тд. +// Наименование - Строка, Неопределено - Наименование элемента +// Реквизиты - Структура, Неопределено - Значения реквизитов элемента +// ПараметрыЗаписи - см. ЮТОбщий.ПараметрыЗаписи +// +// Возвращаемое значение: +// ЛюбаяСсылка - Ссылка на созданный объект +Функция СоздатьЭлемент(Менеджер, Наименование = Неопределено, Реквизиты = Неопределено, Знач ПараметрыЗаписи = Неопределено) Экспорт + + Если Реквизиты <> Неопределено Тогда + Данные = Реквизиты; + Иначе + Данные = Новый Структура; + КонецЕсли; + + Если ЗначениеЗаполнено(Наименование) Тогда + Если ЮТОбщийСлужебныйВызовСервера.ЭтоАнглийскийВстроенныйЯзык() Тогда + Данные.Вставить("Description", Наименование); + Иначе + Данные.Вставить("Наименование", Наименование); + КонецЕсли; + КонецЕсли; + + Ссылка = ЮТТестовыеДанныеСлужебныйВызовСервера.СоздатьЗапись(Менеджер, Данные, ПараметрыЗаписи, Ложь); + ЮТТестовыеДанныеСлужебный.ДобавитьТестовуюЗапись(Ссылка); + + Возврат Ссылка; + +КонецФункции + +// Создает новый документ и возвращает его ссылку. +// +// Параметры: +// Менеджер - Произвольный - Менеджер справочника/ПВХ и тд. +// Реквизиты - Структура, Неопределено - Значения реквизитов элемента +// ПараметрыЗаписи - см. ЮТОбщий.ПараметрыЗаписи +// +// Возвращаемое значение: +// ДокументСсылка - Ссылка на созданный объект +Функция СоздатьДокумент(Менеджер, Реквизиты = Неопределено, Знач ПараметрыЗаписи = Неопределено) Экспорт + + Если Реквизиты <> Неопределено Тогда + Данные = Реквизиты; + Иначе + Данные = Новый Структура; + КонецЕсли; + + Если ПараметрыЗаписи = Неопределено И Данные.Свойство("РежимЗаписи") Тогда + ПараметрыЗаписи = ЮТОбщий.ПараметрыЗаписи(); + ПараметрыЗаписи.РежимЗаписи = Данные.РежимЗаписи; + Данные.Удалить("РежимЗаписи"); + КонецЕсли; + + Ссылка = ЮТТестовыеДанныеСлужебныйВызовСервера.СоздатьЗапись(Менеджер, Данные, ПараметрыЗаписи, Ложь); + ЮТТестовыеДанныеСлужебный.ДобавитьТестовуюЗапись(Ссылка); + + Возврат Ссылка; + +КонецФункции + +// Создает новую группу +// +// Параметры: +// Менеджер - Произвольный - Менеджер справочника/ПВХ и тд. +// Наименование - Строка, Неопределено - Наименование элемента +// Реквизиты - Структура, Неопределено - Значения реквизитов элемента +// ПараметрыЗаписи - см. ЮТОбщий.ПараметрыЗаписи +// +// Возвращаемое значение: +// ЛюбаяСсылка - Ссылка на созданную группу +Функция СоздатьГруппу(Менеджер, Наименование = Неопределено, Реквизиты = Неопределено, Знач ПараметрыЗаписи = Неопределено) Экспорт + + Если Реквизиты <> Неопределено Тогда + Данные = Реквизиты; + Иначе + Данные = Новый Структура; + КонецЕсли; + + Данные.Вставить("ЭтоГруппа", Истина); + + Возврат СоздатьЭлемент(Менеджер, Наименование, Данные, ПараметрыЗаписи); + +КонецФункции + +#Область ГенерацияСлучайныхЗначений + +// Генерирует и возвращает случайное число. +// +// Параметры: +// Минимум - Неопределено, Число - Минимальное значение +// Максимум - Неопределено, Число - Максимальное значение +// ЗнаковПослеЗапятой - Число - Количество знаков после запятой +// +// Возвращаемое значение: +// Число - Случайное число +Функция СлучайноеЧисло(Минимум = 0, Максимум = Неопределено, ЗнаковПослеЗапятой = 0) Экспорт + +#Если ВебКлиент Тогда + ВызватьИсключение ЮТИсключения.МетодНеДоступен("ЮТТестовыеДанные.СлучайноеЧисло"); +#Иначе + Генератор = ЮТКонтекстСлужебный.ЗначениеКонтекста("ГенераторСлучайныхЧисел"); + + Если Генератор = Неопределено Тогда + Генератор = Новый ГенераторСлучайныхЧисел(); + ЮТКонтекстСлужебный.УстановитьЗначениеКонтекста("ГенераторСлучайныхЧисел", Генератор); + КонецЕсли; + + Если Максимум = Неопределено Тогда + Результат = Генератор.СлучайноеЧисло(Минимум); + Иначе + Результат = Генератор.СлучайноеЧисло(Минимум, Максимум); + КонецЕсли; + + Если ЗнаковПослеЗапятой > 0 Тогда + Множитель = Pow(10, ЗнаковПослеЗапятой); + Результат = Результат + Окр(Генератор.СлучайноеЧисло(0, Множитель) / Множитель, ЗнаковПослеЗапятой); + КонецЕсли; + + Возврат Результат; +#КонецЕсли + +КонецФункции + +// Генерирует и возвращает случайное положительное число. +// +// Параметры: +// Максимум - Неопределено, Число - Максимальное значение +// ЗнаковПослеЗапятой - Число - Знаков после запятой +// +// Возвращаемое значение: +// Число - Случайное положительное число +Функция СлучайноеПоложительноеЧисло(Максимум = Неопределено, ЗнаковПослеЗапятой = 0) Экспорт + + Возврат СлучайноеЧисло(1, Максимум, ЗнаковПослеЗапятой); + +КонецФункции + +// Генерирует и возвращает случайное отрицательное число. +// +// Параметры: +// Минимум - Неопределено, Число - Минимальное значение +// ЗнаковПослеЗапятой - Число - Знаков после запятой +// +// Возвращаемое значение: +// Число - Случайное отрицательное число +Функция СлучайноеОтрицательноеЧисло(Знач Минимум = Неопределено, ЗнаковПослеЗапятой = 0) Экспорт + + Если Минимум <> Неопределено Тогда + Минимум = -Минимум; + КонецЕсли; + + Возврат -СлучайноеЧисло(0, Минимум, ЗнаковПослеЗапятой); + +КонецФункции + +// Генерирует и возвращает случайную строку указанной длины, строка может содержать цифры, английские и русские буквы в разных регистрах. +// +// Параметры: +// Длина - Число - Длина генерируемой строки с учетом префикса +// Префикс - Строка - Префикс строки +// ДопустимыеСимволы - Строка - Допустимые символы из которая будет формироваться случайная строка +// +// Возвращаемое значение: +// Строка - Случайная строка +Функция СлучайнаяСтрока(Знач Длина = 10, Префикс = "", Знач ДопустимыеСимволы = Неопределено) Экспорт + + Если ДопустимыеСимволы = Неопределено Тогда + ДопустимыеСимволы = ЮТСтроки.РусскиеБуквы(Истина, Истина) + ЮТСтроки.АнглийскиеБуквы(Истина, Истина) + ЮТСтроки.Цифры(); + КонецЕсли; + + Результат = ""; + КоличествоСимволов = СтрДлина(ДопустимыеСимволы); + + Длина = Длина - СтрДлина(Префикс); + + Для Инд = 1 По Длина Цикл + + Результат = Результат + Сред(ДопустимыеСимволы, СлучайноеЧисло(1, КоличествоСимволов), 1); + + КонецЦикла; + + Возврат Префикс + Результат; + +КонецФункции + +// Возвращяет случайный валидный идентификатор +// +// Параметры: +// Длина - Число - Длина генерируемой строки с учетом префикса +// Префикс - Строка - Префикс строки +// +// Возвращаемое значение: +// Строка - Случайный идентификатор +Функция СлучайныйИдентификатор(Знач Длина = 10, Знач Префикс = "") Экспорт + + НаборСимволов = "_" + ЮТСтроки.РусскиеБуквы(Истина, Истина) + ЮТСтроки.АнглийскиеБуквы(Истина, Истина); + + Если ПустаяСтрока(Префикс) Тогда + Префикс = СлучайнаяСтрока(1, "", НаборСимволов); + КонецЕсли; + + НаборСимволов = НаборСимволов + ЮТСтроки.Цифры(); + + Возврат СлучайнаяСтрока(Длина, Префикс, НаборСимволов); + +КонецФункции + +// Генерирует и возвращает случайную дату в указанном интервале (если не указан используется `0001-01-01 - 3999-12-31`). +// +// Параметры: +// Минимум - Дата - Минимальное значение случайной даты +// - Неопределено - Если не указано используется `0001-01-01` +// Максимум - Дата - Максимальное значение случайной даты +// - Неопределено - Если не указано используется `3999-12-31` +// +// Возвращаемое значение: +// Дата - Случайная дата +Функция СлучайнаяДата(Знач Минимум = '00010101', Знач Максимум = '39991231') Экспорт + + Если Минимум = Максимум Тогда + Возврат Минимум; + ИначеЕсли Максимум < Минимум Тогда + ВызватьИсключение ЮТИсключения.НекорректныеПараметрыМетода("СлучайнаяДата", "максимальное значение должно быть больше минимального"); + КонецЕсли; + + РазностьДат = Максимум - Минимум; + + Если РазностьДат <= МаксимумГенератора() Тогда + Возврат Минимум + СлучайноеЧисло(0, РазностьДат); + КонецЕсли; + + СекундВДне = 86400; + КоличествоДней = Цел((РазностьДат) / СекундВДне); + + Возврат Минимум + СлучайноеЧисло(0, КоличествоДней) * СекундВДне + СлучайноеЧисло(0, СекундВДне); + +КонецФункции + +// Генерирует случайное время +// +// Возвращаемое значение: +// Дата - Случайное время +Функция СлучайноеВремя() Экспорт + + СекундВСутках = 60*60*24; + + Возврат '00010101000000' + СлучайноеЧисло(0, СекундВСутках - 1); + +КонецФункции + +// Генерирует случайную дату в будущем. +// Максимальное значение генерируемой даты можно ограничить параметрами. +// Например: СлучайнаяДатаВБудущем(2, "часа") - будет сформирована дата в интервале (ТекущаяДата, ТекущаяДата + 2 часа] +// +// Параметры: +// Интервал - Число - Интервал +// ТипИнтервала - Строка - Строковое представление интервала времени, возможные значения +// * секунда, секунды, секунд +// * минута, минуты, минут +// * час, часа, часов +// * день, дня, дней +// * месяц, месяца, месяцев +// +// Возвращаемое значение: +// Дата - Случайная дата в будущем +Функция СлучайнаяДатаВБудущем(Интервал = Неопределено, ТипИнтервала = Неопределено) Экспорт + + //@skip-check use-non-recommended-method + Возврат СлучайнаяДатаПосле(ТекущаяДата(), Интервал, ТипИнтервала); + +КонецФункции + +// Генерирует случайную дату в прошлом. +// Минимальное значение генерируемой даты можно ограничить параметрами. +// Например: СлучайнаяДатаВПрошлом(2, "часа") - будет сформирована дата в интервале [ТекущаяДата - 2 часа, ТекущаяДата) +// +// Параметры: +// Интервал - Число - Интервал +// ТипИнтервала - Строка - Строковое представление интервала времени, возможные значения +// * секунда, секунды, секунд +// * минута, минуты, минут +// * час, часа, часов +// * день, дня, дней +// * месяц, месяца, месяцев +// +// Возвращаемое значение: +// Дата - Случайная дата в прошлом +Функция СлучайнаяДатаВПрошлом(Интервал = Неопределено, ТипИнтервала = Неопределено) Экспорт + + //@skip-check use-non-recommended-method + Возврат СлучайнаяДатаДо(ТекущаяДата(), Интервал, ТипИнтервала); + +КонецФункции + +// Генерирует случайную дату, значение которой больше указанной. +// Максимальное значение генерируемой даты можно ограничить параметрами. +// Например: СлучайнаяДатаПосле(Дата, 2, "часа") - будет сформирована дата в интервале [Дата - 2 часа, Дата) +// +// Параметры: +// Дата - Дата +// Интервал - Число - Интервал +// ТипИнтервала - Строка - Строковое представление интервала времени, возможные значения +// * секунда, секунды, секунд +// * минута, минуты, минут +// * час, часа, часов +// * день, дня, дней +// * месяц, месяца, месяцев +// +// Возвращаемое значение: +// Дата +Функция СлучайнаяДатаПосле(Дата, Интервал = Неопределено, ТипИнтервала = Неопределено) Экспорт + + ИнтервалНеУказан = Интервал = Неопределено И ТипИнтервала = Неопределено; + + Если ИнтервалНеУказан Тогда + Возврат СлучайнаяДата(Дата + 1); + Иначе + Минимум = Дата + 1; + Максимум = ЮТОбщий.ДобавитьКДате(Дата, Интервал, ТипИнтервала); + Возврат СлучайнаяДата(Минимум, Максимум); + КонецЕсли; + +КонецФункции + +// Генерирует случайную дату, значение которой меньше указанной. +// Минимальное значение генерируемой даты можно ограничить параметрами. +// Например: СлучайнаяДатаПосле(Дата, 2, "часа") - будет сформирована дата в интервале [Дата - 2 часа, Дата) +// +// Параметры: +// Дата - Дата +// Интервал - Число - Интервал +// ТипИнтервала - Строка - Строковое представление интервала времени, возможные значения +// * секунда, секунды, секунд +// * минута, минуты, минут +// * час, часа, часов +// * день, дня, дней +// * месяц, месяца, месяцев +// +// Возвращаемое значение: +// Дата +Функция СлучайнаяДатаДо(Дата, Интервал = Неопределено, ТипИнтервала = Неопределено) Экспорт + + ИнтервалНеУказан = Интервал = Неопределено И ТипИнтервала = Неопределено; + + Если ИнтервалНеУказан Тогда + Возврат СлучайнаяДата(, Дата - 1); + Иначе + Минимум = ЮТОбщий.ДобавитьКДате(Дата, -Интервал, ТипИнтервала); + Максимум = Дата - 1; + Возврат СлучайнаяДата(Минимум, Максимум); + КонецЕсли; + +КонецФункции + +// Генерирует и возвращает случайный IP адрес. +// +// Возвращаемое значение: +// Строка - Случайный IP адрес +Функция СлучайныйIPАдрес() Экспорт + + Части = Новый Массив(); + Части.Добавить(СлучайноеЧисло(1, 253)); + Части.Добавить(СлучайноеЧисло(1, 253)); + Части.Добавить(СлучайноеЧисло(1, 253)); + Части.Добавить(СлучайноеЧисло(1, 253)); + + Возврат СтрСоединить(Части, "."); + +КонецФункции + +// Возвращает случайный элемент списка. +// +// Параметры: +// Список - Массив из Произвольный - Коллекция возможных значений +// +// Возвращаемое значение: +// Произвольный - случайное значение из списка +Функция СлучайноеЗначениеИзСписка(Список) Экспорт + + Индекс = СлучайноеЧисло(0, Список.ВГраница()); + + Возврат Список[Индекс]; + +КонецФункции + +// Возвращает случайное логическое значение. +// +// Возвращаемое значение: +// Булево - Случайное булево +Функция СлучайноеБулево() Экспорт + + Возврат СлучайноеЧисло() % 2 = 0; + +КонецФункции + +// Возвращает случайное значение перечисления +// +// Параметры: +// Перечисление - ПеречислениеМенеджер - Менеджер +// - Строка - Имя объекта метаданных +// +// Возвращаемое значение: +// ПеречислениеСсылка +Функция СлучайноеЗначениеПеречисления(Перечисление) Экспорт + + Возврат ЮТТестовыеДанныеСлужебныйВызовСервера.СлучайноеЗначениеПеречисления(Перечисление); + +КонецФункции + +// Возвращает случайное предопреленное значения объекта конфигурации. +// +// Параметры: +// Менеджер - Строка - Имя менеджера. Примеры: "Справочники.ВидыЦен", "Справочник.ВидыЦен" +// - Произвольный - Менеджер объекта метаданных. Примеры: Справочники.ВидыЦен +// Отбор - Структура, Соответствие из Произвольный - Отбора поиска предопределенных значений (сравнение на равенство) +// +// Возвращаемое значение: +// ПеречислениеСсылка +Функция СлучайноеПредопределенноеЗначение(Менеджер, Отбор = Неопределено) Экспорт + + Возврат ЮТТестовыеДанныеСлужебныйВызовСервера.СлучайноеПредопределенноеЗначение(Менеджер, Отбор); + +КонецФункции + +// Возвращает случайный номер телефона. +// +// Параметры: +// КодСтраны - Строка - Код страны, с которого будет начинаться номер. +// +// Возвращаемое значение: +// Строка - Сгенерированный номер телефона. +Функция СлучайныйНомерТелефона(КодСтраны = "7") Экспорт + Результат = СтрШаблон( + "+%1(%2)%3-%4-%5", + ?(ПустаяСтрока(КодСтраны), "7", КодСтраны), + Формат(СлучайноеЧисло(0, 999), "ЧЦ=3; ЧН=000; ЧВН=; ЧГ=0;"), + Формат(СлучайноеЧисло(0, 999), "ЧЦ=3; ЧН=000; ЧВН=; ЧГ=0;"), + Формат(СлучайноеЧисло(0, 99), "ЧЦ=2; ЧН=00; ЧВН=; ЧГ=0;"), + Формат(СлучайноеЧисло(0, 99), "ЧЦ=2; ЧН=00; ЧВН=; ЧГ=0;") + ); + + Возврат Результат; +КонецФункции + +#КонецОбласти + +// Генерирует и возвращает уникальную строку, формируется из уникального идентификатора. +// +// Параметры: +// Префикс - Строка - Префикс строки +// +// Возвращаемое значение: +// Строка - Уникальная строка +Функция УникальнаяСтрока(Префикс = "") Экспорт + + Возврат Префикс + Новый УникальныйИдентификатор(); + +КонецФункции + +#Если Не ВебКлиент Тогда + +// Создает новый файл, который будет удален после теста +// +// Параметры: +// Содержимое - Строка, Неопределено - Содержимое файла +// ТолькоЧтение - Булево - Установить атрибут `только чтение` +// Расширение - Строка, Неопределено - Расширение нового файла +// +// Возвращаемое значение: +// Строка - Новый файл +Функция НовыйФайл(Содержимое = Неопределено, ТолькоЧтение = Ложь, Расширение = Неопределено) Экспорт + + Результат = НовоеИмяВременногоФайла(Расширение); + + ЗаписьДанных = Новый ЗаписьДанных(Результат); + + Если Содержимое <> Неопределено Тогда + ЗаписьДанных.ЗаписатьСимволы(Содержимое); + КонецЕсли; + + ЗаписьДанных.Закрыть(); + + Если ТолькоЧтение Тогда + СозданныйФайл = Новый Файл(Результат); + СозданныйФайл.УстановитьТолькоЧтение(Истина); + КонецЕсли; + + Возврат Результат; + +КонецФункции + +// Возвращает имя нового файла. +// По окончании выполнения теста этот файл будет удален. +// +// Параметры: +// Расширение - Строка - Расширение нового файла +// +// Возвращаемое значение: +// Строка +Функция НовоеИмяВременногоФайла(Расширение = Неопределено) Экспорт + + Возврат ЮТТестовыеДанныеСлужебный.НовоеИмяВременногоФайла(Расширение); + +КонецФункции + +// Читает таблицу MarkDown в массив структур +// +// Параметры: +// Строки - Строка - Таблица markdown +// +// Возвращаемое значение: +// Массив из Структура - Данные таблицы markdown +Функция ТаблицаMarkDown(Строки) Экспорт + + ЗагрузилиЗаголовок = Ложь; + Результат = Новый Массив(); + Ключи = ""; + + Разделитель = "|"; + + Кодировка = КодировкаТекста.UTF8; + Поток = ПолучитьДвоичныеДанныеИзСтроки(Строки, Кодировка).ОткрытьПотокДляЧтения(); + Чтение = Новый ЧтениеТекста(Поток, Кодировка); + + Пока Истина Цикл + + Строка = Чтение.ПрочитатьСтроку(); + Если Строка = Неопределено Тогда + Прервать; + КонецЕсли; + + Строка = СокрЛП(Строка); + + Если ПустаяСтрока(Строка) Тогда + Продолжить; + ИначеЕсли НЕ СтрНачинаетсяС(Строка, Разделитель) Тогда + Если ЗагрузилиЗаголовок Тогда + Прервать; + Иначе + Продолжить; + КонецЕсли; + КонецЕсли; + + Блоки = СтрРазделить(Строка, Разделитель); + + Если ЗагрузилиЗаголовок Тогда + + Если Блоки.Количество() <> Ключи.Количество() Тогда + ВызватьИсключение СтрШаблон("Количество значений в строке (%1) Markdown не совпадает с количеством заголовков (%2): + |%3", Блоки.Количество(), Ключи.Количество(), Строка); + КонецЕсли; + + СтрокаРезультата = Новый Структура(); + Для Инд = 1 По Блоки.ВГраница() - 1 Цикл + СтрокаРезультата.Вставить(Ключи[Инд], СокрЛП(Блоки[Инд])); + КонецЦикла; + Результат.Добавить(СтрокаРезультата); + Иначе + Ключи = Новый Массив(); + Для Инд = 0 По Блоки.ВГраница() Цикл + Ключи.Добавить(СокрЛП(Блоки[Инд])); + КонецЦикла; + Чтение.ПрочитатьСтроку(); // Пропуск строки разделителя + ЗагрузилиЗаголовок = Истина; + КонецЕсли; + + КонецЦикла; + + Чтение.Закрыть(); + Поток.Закрыть(); + + Возврат Результат; + +КонецФункции + +// Формирует структуру на основании таблицы Markdown +// +// Параметры: +// Ключ - Строка - Имя ключевой колонки +// Строки - Строка - Таблица markdown +// +// Возвращаемое значение: +// Структура +Функция СтруктураMarkDown(Ключ, Строки) Экспорт + + Таблица = ТаблицаMarkDown(Строки); + + Результат = Новый Структура(); + + Для Каждого Строка Из Таблица Цикл + Результат.Вставить(Строка[Ключ], Строка); + КонецЦикла; + + Возврат Результат; + +КонецФункции + +#КонецЕсли + +// Формирует массив различных комбиначий параметров +// +// Предназначено для формирования таблицы возможных значений параметров для краш теста метода. +// +// Параметры: +// ЗначенияПоУмолчанию - Структура - Значения параметров по умолчанию. +// ЗначенияПараметров - Структура - Массивы значений для каждого параметра. +// +// Возвращаемое значение: +// Массив из Структура - Варианты параметров. +Функция ВариантыПараметров(ЗначенияПоУмолчанию, ЗначенияПараметров) Экспорт + + Варианты = Новый Массив; + Варианты.Добавить(ЗначенияПоУмолчанию); + + Ключи = ЮТКоллекции.ВыгрузитьЗначения(ЗначенияПараметров, "Ключ"); + + ДобавитьВарианты(Варианты, ЗначенияПоУмолчанию, ЗначенияПараметров, Ключи, 0); + + Возврат Варианты; + +КонецФункции + +// Возвращает конструктор создания тестовых данных +// +// Конструктор имеет ряд особенностей: +// +// * Нельзя использовать параллельно несколько конструкторов. +// Например +// +// ```bsl +// Пользователь = КонструкторОбъекта(Справочники.Пользователи); +// Документ = КонструкторОбъекта(Документы.Приход); +// ... +// Пользователь.Записать(); +// Документ.Провести(); +// ``` +// +// * Создание объекта происходит при вызове методов `Записать` и `Провести`, а создание реквизитов происходит во время вызова методов установки. +// * При использовании на клиенте все значения должны быть сериализуемыми. +// +// Параметры: +// Менеджер - Строка - Имя менеджера. Примеры: "Справочники.Товары", "Документы.ПриходТоваров" +// - Произвольный - Менеджер объекта метаданных. Примеры: Справочники.Товары, Документы.ПриходТоваров +// Возвращаемое значение: +// ОбработкаОбъект.ЮТКонструкторТестовыхДанных +Функция КонструкторОбъекта(Менеджер) Экспорт + + Возврат ЮТКонструкторТестовыхДанныхСлужебный.Инициализировать(Менеджер); + +КонецФункции + +#Если Сервер Или ТолстыйКлиентОбычноеПриложение Тогда +// Возвращает конструктор создания объекта XDTO +// +// Параметры: +// ИмяТипа - Строка - Имя типа объекта +// ПространствоИмен - Строка - Пространство имен типа +// Фабрика - ФабрикаXDTO - Используемая фабрика XDTO +// +// Возвращаемое значение: +// ОбработкаОбъект.ЮТКонструкторОбъектаXDTO - Конструктор объекта XDTO +Функция КонструкторОбъектаXDTO(ИмяТипа, ПространствоИмен, Фабрика = Неопределено) Экспорт + + Обработка = Обработки.ЮТКонструкторОбъектаXDTO.Создать(); + Обработка.Инициализировать(ИмяТипа, ПространствоИмен, Фабрика); + + Возврат Обработка; + +КонецФункции +#КонецЕсли + +// Удаляет переданные объекта +// +// Параметры: +// Ссылки - Массив из ЛюбаяСсылка +Процедура Удалить(Ссылки) Экспорт + + Если ЗначениеЗаполнено(Ссылки) Тогда + ЮТТестовыеДанныеСлужебныйВызовСервера.Удалить(Ссылки); + КонецЕсли; + +КонецПроцедуры + +// Возвращает объект подражателя для формирования осмысленных тестовых данных +// +// Возвращаемое значение: +// ОбщийМодуль - Подражатель +Функция Подражатель() Экспорт + + Возврат ЮТПодражательСлужебный.Инициализировать(); + +КонецФункции + +// Возвращает таблицу значений из табличного документа +// +// Параметры: +// Макет - ТабличныйДокумент - Исходный табличный документ +// ОписанияТипов - Соответствие из ОписаниеТипов - Соответствие имен колонок таблицы к типам значений +// КэшЗначений - Соответствие из Произвольный - Соответствие для хранения создаваемых значений +// ЗаменяемыеЗначения - Соответствие из Произвольный - Значения, использующиеся для замены +// ПараметрыСозданияОбъектов - см. ЮТФабрика.ПараметрыСозданияОбъектов +// Возвращаемое значение: +// - ТаблицаЗначений - Для сервера, данные загруженные из макета +// - Массив из Структура - Для клиента, данные загруженные из макета +Функция ЗагрузитьИзМакета(Макет, + ОписанияТипов, + КэшЗначений = Неопределено, + ЗаменяемыеЗначения = Неопределено, + ПараметрыСозданияОбъектов = Неопределено) Экспорт + +#Если Сервер Тогда + ТаблицаЗначений = Истина; +#Иначе + ТаблицаЗначений = Ложь; +#КонецЕсли + + Если Макет = Неопределено Тогда + ВызватьИсключение "Укажите источник данных (Макет)"; + КонецЕсли; + + Если НЕ ЗначениеЗаполнено(ОписанияТипов) Тогда + ВызватьИсключение "Укажите описание загружаемых колонок (ОписанияТипов)"; + КонецЕсли; + + ЮТПроверкиСлужебный.ПроверитьТипПараметра(ОписанияТипов, "Структура, Соответствие", "ЮТТестовыеДанные.ЗагрузитьИзМакета", "ОписанияТипов"); + + Возврат ЮТТестовыеДанныеСлужебный.ЗагрузитьИзМакета(Макет, + ОписанияТипов, + КэшЗначений, + ЗаменяемыеЗначения, + ПараметрыСозданияОбъектов, + ТаблицаЗначений); + +КонецФункции + +#Если Сервер Тогда +// Возвращает мок для `HTTPСервисЗапрос`. +// +// Возвращаемое значение: +// ОбработкаОбъект.ЮТHTTPСервисЗапрос - Мок +Функция HTTPСервисЗапрос() Экспорт + + Если ЮТОбщийСлужебныйВызовСервера.ЭтоАнглийскийВстроенныйЯзык() Тогда + Возврат Обработки.ЮТHTTPServiceRequest.Создать(); + Иначе + Возврат Обработки.ЮТHTTPСервисЗапрос.Создать(); + КонецЕсли; + +КонецФункции +#КонецЕсли + +#Если Сервер Или ТолстыйКлиентОбычноеПриложение Тогда +// Возвращает мок для ADO.RecordSet. +// +// Параметры: +// Колонки - Строка - Имена колонок набора данных, разделенные запятой +// Описание - Строка - Описание, полезно для отладки и проверки +// +// Возвращаемое значение: +// ОбработкаОбъект.ЮТRecordSet - Мок ADO.RecordSet +Функция ADORecordSet(Колонки, Описание = Неопределено) Экспорт + + Обработка = Обработки.ЮТRecordSet.Создать(); + Обработка.Описание = Описание; + Обработка.Инициализировать(Колонки); + + Возврат Обработка; + +КонецФункции +#КонецЕсли + +// Устанавливает значение реквизита ссылки +// +// Параметры: +// Ссылка - ЛюбаяСсылка +// ИмяРеквизита - Строка +// ЗначениеРеквизита - Произвольный +// ПараметрыЗаписи - см. ЮТФабрикаСлужебный.ПараметрыЗаписи +Процедура УстановитьЗначениеРеквизита(Ссылка, ИмяРеквизита, ЗначениеРеквизита, ПараметрыЗаписи = Неопределено) Экспорт + + Значения = Новый Соответствие(); + Значения.Вставить(ИмяРеквизита, ЗначениеРеквизита); + УстановитьЗначенияРеквизитов(Ссылка, Значения, ПараметрыЗаписи); + +КонецПроцедуры + +// Устанавливает значения реквизитов ссылки. +// +// Параметры: +// Ссылка - ЛюбаяСсылка - Ссылка +// ЗначенияРеквизитов - Структура, Соответствие из Произвольный - Значения реквизитов +// ПараметрыЗаписи - см. ЮТФабрикаСлужебный.ПараметрыЗаписи +Процедура УстановитьЗначенияРеквизитов(Ссылка, ЗначенияРеквизитов, ПараметрыЗаписи = Неопределено) Экспорт + + ЮТТестовыеДанныеСлужебныйВызовСервера.УстановитьЗначенияРеквизитов(Ссылка, ЗначенияРеквизитов); + +КонецПроцедуры + +// Генерирует новое значение указанного типа. +// Если `ОписаниеТипа` содержит несколько типов, то выбирается случайный из них. +// Параметры: +// ОписаниеТипа - ОписаниеТипов, Тип - Тип значения генерируемого значения +// РеквизитыЗаполнения - Структура - Значения реквизитов заполнения создаваемого объекта базы +// - Неопределено +// +// Возвращаемое значение: +// Произвольный - Сгенерированное значение указанного типа +Функция Фикция(ОписаниеТипа, РеквизитыЗаполнения = Неопределено) Экспорт + + Возврат ЮТТестовыеДанныеСлужебный.Фикция(ОписаниеТипа, РеквизитыЗаполнения); + +КонецФункции + +#КонецОбласти + +#Область СлужебныеПроцедурыИФункции + +Процедура ДобавитьВарианты(Варианты, БазоваяСтруктура, ЗначенияПараметров, Ключи, Инд) + + Если Инд > Ключи.ВГраница() Тогда + Возврат; + КонецЕсли; + + Ключ = Ключи[Инд]; + Для Каждого Значение Из ЗначенияПараметров[Ключ] Цикл + + Вариант = ЮТКоллекции.СкопироватьСтруктуру(БазоваяСтруктура); + Вариант[Ключ] = Значение; + Варианты.Добавить(Вариант); + + ДобавитьВарианты(Варианты, Вариант, ЗначенияПараметров, Ключи, Инд + 1); + + КонецЦикла; + +КонецПроцедуры + +Функция МножительПериода(ТипИнтервала) + + Множители = ЮТСлужебныйПовторногоИспользования.МножителиИнтервалов(); + Возврат Множители[ТипИнтервала]; + +КонецФункции + +Функция ЭтоМесяц(ТипИнтервала) + + Возврат СтрСравнить(ТипИнтервала, "месяц") = 0 + Или СтрСравнить(ТипИнтервала, "месяца") = 0 + Или СтрСравнить(ТипИнтервала, "месяцев") = 0; + +КонецФункции + +Функция МаксимумГенератора() + + Возврат 4294967295; + +КонецФункции + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТТестовыеДанныеСлужебный.xml b/src/cfe/YAXUnit/CommonModules/ЮТТестовыеДанныеСлужебный.xml new file mode 100644 index 0000000..8bfc1a9 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТТестовыеДанныеСлужебный.xml @@ -0,0 +1,23 @@ + + + + + ЮТТестовыеДанныеСлужебный + + + ru + Тестовые данные (служебный) + + + + false + true + true + false + true + false + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТТестовыеДанныеСлужебный/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТТестовыеДанныеСлужебный/Ext/Module.bsl new file mode 100644 index 0000000..c4b52c4 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТТестовыеДанныеСлужебный/Ext/Module.bsl @@ -0,0 +1,254 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область СлужебныйПрограммныйИнтерфейс + +// см. ЮТТестовыеДанные.Фикция +Функция Фикция(ОписаниеТипа, РеквизитыЗаполнения = Неопределено) Экспорт + + ПереданоОписаниеТипа = ТипЗнч(ОписаниеТипа) = Тип("ОписаниеТипов"); + + Если НЕ ПереданоОписаниеТипа Тогда + Тип = ОписаниеТипа; + ИначеЕсли ОписаниеТипа.Типы().Количество() > 1 Тогда + НомерТипа = ЮТТестовыеДанные.СлучайноеПоложительноеЧисло(ОписаниеТипа.Типы().Количество()); + Тип = ОписаниеТипа.Типы()[НомерТипа - 1]; + Иначе + Тип = ОписаниеТипа.Типы()[0]; + КонецЕсли; + + Значение = Неопределено; + + Если Тип = Тип("Число") Тогда + + Значение = ФиктивноеЧисло(ОписаниеТипа); + + ИначеЕсли Тип = Тип("Строка") Тогда + + Значение = ФикстивнаяСтрока(ОписаниеТипа); + + ИначеЕсли Тип = Тип("Дата") Тогда + + Значение = ФикстивнаяДата(ОписаниеТипа); + + ИначеЕсли Тип = Тип("Булево") Тогда + + Значение = ЮТТестовыеДанные.СлучайноеБулево(); + + ИначеЕсли ЮТТипыДанныхСлужебный.ЭтоСистемноеПеречисление(Тип) Тогда + + Значение = СлучайноЗначениеСистемногоПеречисления(Тип); + + Иначе + + Значение = ЮТТестовыеДанныеСлужебныйВызовСервера.ФикцияЗначенияБазы(Тип, РеквизитыЗаполнения); + ДобавитьТестовуюЗапись(Значение); + + КонецЕсли; + + Если Значение = Неопределено Тогда + ВызватьИсключение СтрШаблон("Создание фейковых значений для `%1` не поддерживается", ОписаниеТипа); + КонецЕсли; + + Если ПереданоОписаниеТипа Тогда + Значение = ОписаниеТипа.ПривестиЗначение(Значение); + КонецЕсли; + + Возврат Значение; + +КонецФункции + +#Если Не ВебКлиент Тогда + +// см. ЮТТестовыеДанные.НовоеИмяВременногоФайла +Функция НовоеИмяВременногоФайла(Расширение = Неопределено) Экспорт + + //@skip-check missing-temporary-file-deletion + Результат = ПолучитьИмяВременногоФайла(Расширение); // BSLLS:MissingTemporaryFileDeletion-off + ДобавитьВременныйФайл(Результат); + Возврат Результат; + +КонецФункции + +#КонецЕсли + +Процедура ДобавитьВременныйФайл(Файл) Экспорт + + БуферВременныеФайлы().Добавить(Файл); + +КонецПроцедуры + +Процедура ДобавитьТестовуюЗапись(Запись) Экспорт + +#Если Сервер Тогда + Если ТранзакцияАктивна() И ЮТНастройкиВыполнения.ВТранзакции() Тогда + Возврат; + КонецЕсли; +#КонецЕсли + Если ЮТНастройкиВыполнения.УдалениеТестовыхДанных() Тогда + БуферТестовыеДанные().Добавить(Запись); + КонецЕсли; + +КонецПроцедуры + +Процедура УдалитьТестовыеДанные() Экспорт + + ЮТФайлы.УдалитьВременныеФайлы(БуферВременныеФайлы()); + + Если ЮТНастройкиВыполнения.УдалениеТестовыхДанных() Тогда + ЮТТестовыеДанные.Удалить(БуферТестовыеДанные()); + КонецЕсли; + +КонецПроцедуры + +// Возвращает соответствие с подстроками поиска и замены +// Возвращаемое значение: +// Соответствие из Строка +Функция ПодстрокиДляЗаменыВИменахСвойств() Экспорт + + ЗаменяемыеПодстроки = Новый Соответствие; + ЗаменяемыеПодстроки.Вставить(".", "_tchk_"); + + Возврат ЗаменяемыеПодстроки; + +КонецФункции + +#Область ОбработчикиСобытий + +Процедура ПослеКаждогоТеста(ОписаниеСобытия) Экспорт + + УдалитьТестовыеДанные(); // Очистка тестовых данных на уровне теста + +КонецПроцедуры + +Процедура ПослеТестовогоНабора(ОписаниеСобытия) Экспорт + + УдалитьТестовыеДанные(); // Очистка тестовых данных на уровне теста + +КонецПроцедуры + +Процедура ПослеВсехТестов(ОписаниеСобытия) Экспорт + + УдалитьТестовыеДанные(); // Очистка тестовых данных на уровне теста + +КонецПроцедуры + +#КонецОбласти + +Функция ЗагрузитьИзМакета(Макет, ОписанияТипов, КэшЗначений, ЗаменяемыеЗначения, ПараметрыСозданияОбъектов, ТаблицаЗначений) Экспорт + + ПараметрыЗаполнения = ЮТФабрикаСлужебный.ПараметрыЗаполненияТаблицыЗначений(ПараметрыСозданияОбъектов); + + Возврат ЮТТестовыеДанныеСлужебныйВызовСервера.ЗагрузитьИзМакета(Макет, + ОписанияТипов, + КэшЗначений, + ЗаменяемыеЗначения, + ПараметрыЗаполнения, + ТаблицаЗначений); + +КонецФункции + +#КонецОбласти + +#Область СлужебныеПроцедурыИФункции + +Функция СлучайноЗначениеСистемногоПеречисления(Тип) + + Менеджер = ЮТМетодыСлужебный.ВычислитьБезопасно(ЮТТипыДанныхСлужебный.ИмяСистемногоПеречисления(Тип)); + + Значения = Новый Массив(); + + Для Каждого Значение Из Менеджер Цикл + Значения.Добавить(Значение); + КонецЦикла; + + Возврат ЮТТестовыеДанные.СлучайноеЗначениеИзСписка(Значения); + +КонецФункции + +Функция БуферВременныеФайлы() + + Возврат Буфер("ВременныеФайлы"); + +КонецФункции + +Функция БуферТестовыеДанные() + + Возврат Буфер("ТестовыеДанные"); + +КонецФункции + +Функция Буфер(Ключ) + + ТекущийКонтекст = ЮТест.Контекст().ТекущийКонтекст(); + + Если ТекущийКонтекст.Свойство(Ключ) Тогда + Буфер = ТекущийКонтекст[Ключ]; + Иначе + Буфер = Новый Массив(); + ТекущийКонтекст.Вставить(Ключ, Буфер); + КонецЕсли; + + Возврат Буфер; + +КонецФункции + +Функция ФиктивноеЧисло(ОписаниеТипа) + + Если ТипЗнч(ОписаниеТипа) <> Тип("ОписаниеТипов") Тогда + Возврат ЮТТестовыеДанные.СлучайноеЧисло(); + КонецЕсли; + + МаксимальноеЗначение = 4294967295; + Если ОписаниеТипа.КвалификаторыЧисла.ДопустимыйЗнак = ДопустимыйЗнак.Неотрицательный ИЛИ ЮТТестовыеДанные.СлучайноеБулево() Тогда + МаксимальноеЗначение = ОписаниеТипа.ПривестиЗначение(МаксимальноеЗначение); + Значение = ЮТТестовыеДанные.СлучайноеПоложительноеЧисло(МаксимальноеЗначение, ОписаниеТипа.КвалификаторыЧисла.РазрядностьДробнойЧасти); + Иначе + МаксимальноеЗначение = ОписаниеТипа.ПривестиЗначение(-МаксимальноеЗначение); + Значение = ЮТТестовыеДанные.СлучайноеОтрицательноеЧисло(МаксимальноеЗначение, ОписаниеТипа.КвалификаторыЧисла.РазрядностьДробнойЧасти); + КонецЕсли; + + Возврат Значение; + +КонецФункции + +Функция ФикстивнаяСтрока(ОписаниеТипа) + + Если ТипЗнч(ОписаниеТипа) <> Тип("ОписаниеТипов") Тогда + Возврат ЮТТестовыеДанные.СлучайнаяСтрока(ЮТТестовыеДанные.СлучайноеПоложительноеЧисло(100)); + КонецЕсли; + + Если ОписаниеТипа.КвалификаторыСтроки.Длина = 0 Тогда + Значение = ЮТТестовыеДанные.СлучайнаяСтрока(ЮТТестовыеДанные.СлучайноеПоложительноеЧисло(100)); + Иначе + Значение = ЮТТестовыеДанные.СлучайнаяСтрока(ОписаниеТипа.КвалификаторыСтроки.Длина); + КонецЕсли; + + Возврат Значение; + +КонецФункции + +Функция ФикстивнаяДата(ОписаниеТипа) + + Интервал = 315360000; // 10 лет + //@skip-check use-non-recommended-method + Возврат ЮТТестовыеДанные.СлучайнаяДата(ТекущаяДата() - Интервал, ТекущаяДата() + Интервал); // BSLLS:DeprecatedCurrentDate-off + +КонецФункции + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТТестовыеДанныеСлужебныйВызовСервера.xml b/src/cfe/YAXUnit/CommonModules/ЮТТестовыеДанныеСлужебныйВызовСервера.xml new file mode 100644 index 0000000..c407192 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТТестовыеДанныеСлужебныйВызовСервера.xml @@ -0,0 +1,23 @@ + + + + + ЮТТестовыеДанныеСлужебныйВызовСервера + + + ru + Тестовые данные (вызов сервера) + + + + false + false + true + false + false + true + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТТестовыеДанныеСлужебныйВызовСервера/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТТестовыеДанныеСлужебныйВызовСервера/Ext/Module.bsl new file mode 100644 index 0000000..93717ab --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТТестовыеДанныеСлужебныйВызовСервера/Ext/Module.bsl @@ -0,0 +1,420 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область СлужебныйПрограммныйИнтерфейс + +Функция СоздатьЗапись(Знач Менеджер, Знач Данные, Знач ПараметрыЗаписи, Знач ВернутьОбъект) Экспорт + + ПараметрыЗаписи = ПараметрыЗаписи(ПараметрыЗаписи); + + Объект = НовыйОбъект(Менеджер, Данные, ПараметрыЗаписи.ДополнительныеСвойства); + + КлючЗаписи = ЗаписатьОбъект(Объект, ПараметрыЗаписи); + + Если ВернутьОбъект Тогда + Возврат Объект; + Иначе + Возврат КлючЗаписи; + КонецЕсли; + +КонецФункции + +// Создает новый объект и заполняет его данными +// +// Параметры: +// Менеджер - Произвольный +// Данные - Структура - Данные заполнения объекта +// ДополнительныеСвойства - Структура - Дополнительные свойства объекта +// +// Возвращаемое значение: +// Произвольный - Созданный объект +Функция НовыйОбъект(Знач Менеджер, Знач Данные, Знач ДополнительныеСвойства = Неопределено) Экспорт + + ОписаниеОбъектаМетаданных = ЮТМетаданные.ОписаниеОбъектаМетаданных(Менеджер); + Менеджер = ЮТОбщий.Менеджер(ОписаниеОбъектаМетаданных); + + ЭтоРегистр = ЮТМетаданные.ЭтоРегистр(ОписаниеОбъектаМетаданных); + + Объект = СоздатьОбъект(Менеджер, ОписаниеОбъектаМетаданных.ОписаниеТипа, Данные); + + Если ДополнительныеСвойства <> Неопределено Тогда + ЮТКоллекции.ДополнитьСтруктуру(Объект.ДополнительныеСвойства, ДополнительныеСвойства); + КонецЕсли; + + Если ЭтоРегистр Тогда + + ЗаполнитьНаборРегистра(Объект, Данные); + Возврат Объект; + + КонецЕсли; + ЗаполнитьЗначенияСвойств(Объект, Данные); + + Если ОписаниеОбъектаМетаданных.ОписаниеТипа.ТабличныеЧасти Тогда + + Для Каждого ОписаниеТабличнойЧасти Из ОписаниеОбъектаМетаданных.ТабличныеЧасти Цикл + + ИмяТабличнойЧасти = ОписаниеТабличнойЧасти.Ключ; + Если НЕ Данные.Свойство(ИмяТабличнойЧасти) Тогда + Продолжить; + КонецЕсли; + + Для Каждого Запись Из Данные[ИмяТабличнойЧасти] Цикл + Строка = Объект[ИмяТабличнойЧасти].Добавить(); + ЗаполнитьЗначенияСвойств(Строка, Запись); + КонецЦикла; + + КонецЦикла; + + КонецЕсли; + + ЗаполнитьБазовыеРеквизиты(Объект, ОписаниеОбъектаМетаданных); + + Возврат Объект; + +КонецФункции + +Процедура Удалить(Знач Ссылки) Экспорт + + Если ТипЗнч(Ссылки) <> Тип("Массив") Тогда + Ссылки = ЮТКоллекции.ЗначениеВМассиве(Ссылки); + КонецЕсли; + + Ошибки = Новый Массив; + + Для Каждого Ссылка Из Ссылки Цикл + + ТипЗначения = ТипЗнч(Ссылка); + Если Ссылка = Неопределено ИЛИ ЮТТипыДанныхСлужебный.ЭтоТипПеречисления(ТипЗначения) Тогда + Продолжить; + КонецЕсли; + + Попытка + Если ЮТТипыДанныхСлужебный.ЭтоСсылочныйТип(ТипЗначения) Тогда + Объект = Ссылка.ПолучитьОбъект(); + Если Объект <> Неопределено Тогда + Объект.Удалить(); + КонецЕсли; + Иначе + Менеджер = ЮТОбщий.Менеджер(ТипЗначения); + Запись = Менеджер.СоздатьМенеджерЗаписи(); + ЗаполнитьЗначенияСвойств(Запись, Ссылка); + Запись.Прочитать(); + Запись.Удалить(); + КонецЕсли; + Исключение + + Ошибки.Добавить(ЮТРегистрацияОшибокСлужебный.ПредставлениеОшибки("Удаление " + Ссылка, ИнформацияОбОшибке())); + + КонецПопытки; + + КонецЦикла; + + ОбновитьНумерациюОбъектов(); + + Если ЗначениеЗаполнено(Ошибки) Тогда + ВызватьИсключение СтрСоединить(Ошибки, Символы.ПС); + КонецЕсли; + +КонецПроцедуры + +Функция ФикцияЗначенияБазы(Знач ТипЗначения, Знач РеквизитыЗаполнения = Неопределено) Экспорт + + ОбъектМетаданных = Метаданные.НайтиПоТипу(ТипЗначения); + + Если ОбъектМетаданных = Неопределено Тогда + Возврат Неопределено; + КонецЕсли; + + Если Метаданные.Перечисления.Содержит(ОбъектМетаданных) Тогда + + Возврат СлучайноеЗначениеПеречисления(ОбъектМетаданных); + + КонецЕсли; + + ОписаниеОбъектаМетаданных = ЮТМетаданные.ОписаниеОбъектаМетаданных(ОбъектМетаданных); + Менеджер = ЮТОбщий.Менеджер(ОбъектМетаданных); + + Объект = СоздатьОбъект(Менеджер, ОписаниеОбъектаМетаданных.ОписаниеТипа, РеквизитыЗаполнения); + + Если ЗначениеЗаполнено(РеквизитыЗаполнения) Тогда + ЗаполнитьЗначенияСвойств(Объект, РеквизитыЗаполнения); + КонецЕсли; + + ЗаполнитьБазовыеРеквизиты(Объект, ОписаниеОбъектаМетаданных); + + Возврат ЗаписатьОбъект(Объект, ПараметрыЗаписи()); + +КонецФункции + +Функция ЗагрузитьИзМакета(Знач Макет, + Знач ОписанияТипов, + КэшЗначений, + Знач ЗаменяемыеЗначения, + Знач ПараметрыЗаполнения, + Знач ТаблицаЗначений) Экспорт + + Таблица = ЮТТестовыеДанныеСлужебныйТаблицыЗначений.ЗагрузитьИзМакета(Макет, + ОписанияТипов, + КэшЗначений, + ЗаменяемыеЗначения, + ПараметрыЗаполнения); + + Если ТаблицаЗначений Тогда + Возврат Таблица; + КонецЕсли; + + Реквизиты = СтрСоединить(ЮТКоллекции.ВыгрузитьЗначения(Таблица.Колонки, "Имя"), ","); + Результат = Новый Массив(Таблица.Количество()); + + Для Инд = 0 По Таблица.Количество() - 1 Цикл + Запись = Новый Структура(Реквизиты); + ЗаполнитьЗначенияСвойств(Запись, Таблица[Инд]); + Результат[Инд] = Запись; + КонецЦикла; + + Возврат Результат; + +КонецФункции + +Функция СлучайноеЗначениеПеречисления(Знач Перечисление) Экспорт + + Менеджер = ЮТОбщий.Менеджер(Перечисление); + + НомерЗначения = ЮТТестовыеДанные.СлучайноеПоложительноеЧисло(Менеджер.Количество()); + Возврат Менеджер.Получить(НомерЗначения - 1); + +КонецФункции + +Функция СлучайноеПредопределенноеЗначение(Менеджер, Отбор) Экспорт + + ИмяТаблицы = ЮТМетаданные.НормализованноеИмяТаблицы(Менеджер); + Условия = ЮТест.Предикат(Отбор) + .Реквизит("Предопределенный").Равно(Истина); + + ОписаниеЗапроса = ЮТЗапросыСлужебныйКлиентСервер.ОписаниеЗапроса(ИмяТаблицы, Условия, "Ссылка"); + + Данные = ЮТЗапросы.РезультатЗапроса(ОписаниеЗапроса); + + Если Данные.Количество() = 1 Тогда + Значение = Данные[0].Ссылка; + ИначеЕсли Данные.Количество() > 1 Тогда + Индекс = ЮТест.Данные().СлучайноеЧисло(0, Данные.Количество() - 1); + Значение = Данные[Индекс].Ссылка; + Иначе + Значение = Неопределено; + КонецЕсли; + + Возврат Значение; + +КонецФункции + +Процедура УстановитьЗначенияРеквизитов(Знач Ссылка, Знач ЗначенияРеквизитов, Знач ПараметрыЗаписи = Неопределено) Экспорт + + Объект = Ссылка.ПолучитьОбъект(); + ПараметрыЗаписи = ПараметрыЗаписи(ПараметрыЗаписи); + + Для Каждого Элемент Из ЗначенияРеквизитов Цикл + Объект[Элемент.Ключ] = Элемент.Значение; + КонецЦикла; + + ЗаписатьОбъект(Объект, ПараметрыЗаписи); + +КонецПроцедуры + +#КонецОбласти + +#Область СлужебныеПроцедурыИФункции + +// Создать объект. +// +// Параметры: ОписаниеМенеджера - +// См. ОписаниеМенеджера +// Менеджер - Произвольный - Менеджер +// ОписаниеТипа - см. ЮТМетаданные.СтруктураОписанияОбъектаМетаданных +// Данные - Структура +// Возвращаемое значение: +// Произвольный - Создать объект +Функция СоздатьОбъект(Менеджер, ОписаниеТипа, Данные) + + Если ОписаниеТипа.Конструктор = "СоздатьЭлемент" Тогда + + ЭтоГруппа = ?(Данные = Неопределено, Ложь, ЮТКоллекции.ЗначениеСтруктуры(Данные, "ЭтоГруппа", Ложь)); + Если ЭтоГруппа Тогда + Результат = Менеджер.СоздатьГруппу(); + Иначе + Результат = Менеджер.СоздатьЭлемент(); + КонецЕсли; + + ИначеЕсли ОписаниеТипа.Конструктор = "СоздатьДокумент" Тогда + Результат = Менеджер.СоздатьДокумент(); + ИначеЕсли ОписаниеТипа.Конструктор = "СоздатьСчет" Тогда + Результат = Менеджер.СоздатьСчет(); + ИначеЕсли ОписаниеТипа.Конструктор = "СоздатьВидРасчета" Тогда + Результат = Менеджер.СоздатьВидРасчета(); + ИначеЕсли ОписаниеТипа.Конструктор = "СоздатьУзел" Тогда + Результат = Менеджер.СоздатьУзел(); + ИначеЕсли ОписаниеТипа.Конструктор = "СоздатьНаборЗаписей" Тогда + Результат = Менеджер.СоздатьНаборЗаписей(); + ИначеЕсли ОписаниеТипа.Конструктор = "СоздатьМенеджерЗаписи" Тогда + Результат = Менеджер.СоздатьМенеджерЗаписи(); + ИначеЕсли ОписаниеТипа.Конструктор = "СоздатьБизнесПроцесс" Тогда + Результат = Менеджер.СоздатьБизнесПроцесс(); + ИначеЕсли ОписаниеТипа.Конструктор = "СоздатьЗадачу" Тогда + Результат = Менеджер.СоздатьЗадачу(); + Иначе + ВызватьИсключение СтрШаблон("Для %1 не поддерживается создание записей ИБ", ОписаниеТипа.Имя); + КонецЕсли; + + Возврат Результат; + +КонецФункции + +// Записать объект. +// +// Параметры: +// Объект - Произвольный - Объект +// ПараметрыЗаписи - см. ЮТОбщий.ПараметрыЗаписи +// +// Возвращаемое значение: +// ЛюбаяСсылка +Функция ЗаписатьОбъект(Объект, ПараметрыЗаписи) + + Если ПараметрыЗаписи.ОбменДаннымиЗагрузка Тогда + Объект.ОбменДанными.Загрузка = Истина; + КонецЕсли; + + Попытка + + Если ПараметрыЗаписи.РежимЗаписи <> Неопределено Тогда + Объект.Записать(ПараметрыЗаписи.РежимЗаписи); + Иначе + Объект.Записать(); + КонецЕсли; + + Если ПараметрыЗаписи.ОбменДаннымиЗагрузка Тогда + Объект.ОбменДанными.Загрузка = Ложь; + КонецЕсли; + + Возврат КлючЗаписи(Объект); + + Исключение + + ЮТРегистрацияОшибок.ДобавитьПояснениеОшибки(СтрШаблон("Не удалось записать объект `%1` (%2)", Объект, ТипЗнч(Объект))); + ВызватьИсключение; + + КонецПопытки; + +КонецФункции + +Процедура ЗаполнитьБазовыеРеквизиты(Объект, ОписаниеОбъектаМетаданных) + + АнглийскийЯзык = ЮТОбщийСлужебныйВызовСервера.ЭтоАнглийскийВстроенныйЯзык(); + ИмяТипаДокумент = ?(АнглийскийЯзык, "Document", "Документ"); + ИмяРеквизитаКод = ?(АнглийскийЯзык, "Code", "Код"); + ИмяРеквизитаНаименование = ?(АнглийскийЯзык, "Description", "Наименование"); + + ОписаниеТипа = ОписаниеОбъектаМетаданных.ОписаниеТипа; + Если ОписаниеТипа.Имя = ИмяТипаДокумент Тогда + Если НЕ ЗначениеЗаполнено(Объект.Дата) Тогда + Объект.Дата = ТекущаяДатаСеанса(); + КонецЕсли; + Если НЕ ЗначениеЗаполнено(Объект.Номер) Тогда + Объект.УстановитьНовыйНомер(); + КонецЕсли; + КонецЕсли; + + Если ОписаниеОбъектаМетаданных.Реквизиты.Свойство(ИмяРеквизитаКод) + И ОписаниеОбъектаМетаданных.Реквизиты[ИмяРеквизитаКод].Обязательный + И НЕ ЗначениеЗаполнено(Объект.Код) Тогда + Объект.УстановитьНовыйКод(); + КонецЕсли; + + Если ОписаниеОбъектаМетаданных.Реквизиты.Свойство(ИмяРеквизитаНаименование) + И ОписаниеОбъектаМетаданных.Реквизиты[ИмяРеквизитаНаименование].Обязательный + И НЕ ЗначениеЗаполнено(Объект.Наименование) Тогда + Объект.Наименование = ЮТТестовыеДанные.СлучайнаяСтрока(); + КонецЕсли; + +КонецПроцедуры + +Функция КлючЗаписи(Объект) + + ТипЗначения = ТипЗнч(Объект); + + Если ЮТТипыДанныхСлужебный.ЭтоТипОбъекта(ТипЗначения) Тогда + + Возврат Объект.Ссылка; + + ИначеЕсли ЮТТипыДанныхСлужебный.ЭтоМенеджерЗаписи(ТипЗначения) Тогда + + Описание = ЮТМетаданные.ОписаниеОбъектаМетаданных(Объект); + + КлючевыеРеквизиты = Новый Структура(); + Для Каждого Реквизит Из Описание.Реквизиты Цикл + Если Реквизит.Значение.ЭтоКлюч Тогда + КлючевыеРеквизиты.Вставить(Реквизит.Ключ, Объект[Реквизит.Ключ]); + КонецЕсли; + КонецЦикла; + + Менеджер = ЮТОбщий.Менеджер(Описание); + Возврат Менеджер.СоздатьКлючЗаписи(КлючевыеРеквизиты); + + ИначеЕсли ЮТТипыДанныхСлужебный.ЭтоТипНабораЗаписей(ТипЗначения) Тогда + + КлючевыеРеквизиты = Новый Структура(); + + Для Каждого ЭлементОтбора Из Объект.Отбор Цикл + КлючевыеРеквизиты.Вставить(ЭлементОтбора.Имя, ЭлементОтбора.Значение); + КонецЦикла; + + Менеджер = ЮТОбщий.Менеджер(Объект); + Возврат Менеджер.СоздатьКлючЗаписи(КлючевыеРеквизиты); + + Иначе + + Сообщение = ЮТИсключения.НеподдерживаемыйПараметрМетода("ЮТТестовыеДанныеВызовСервера.КлючЗаписи", Объект); + ВызватьИсключение Сообщение; + + КонецЕсли; + +КонецФункции + +Функция ПараметрыЗаписи(ВходящиеПараметрыЗаписи = Неопределено) + + Если ВходящиеПараметрыЗаписи = Неопределено Тогда + Возврат ЮТОбщий.ПараметрыЗаписи(); + Иначе + ПараметрыЗаписи = ЮТОбщий.ПараметрыЗаписи(); + ЗаполнитьЗначенияСвойств(ПараметрыЗаписи, ВходящиеПараметрыЗаписи); + Возврат ПараметрыЗаписи; + КонецЕсли; + +КонецФункции + +Процедура ЗаполнитьНаборРегистра(Набор, ДанныеЗаписи) + + Запись = Набор.Добавить(); + ЗаполнитьЗначенияСвойств(Запись, ДанныеЗаписи); + + Для Каждого ЭлементОтбора Из Набор.Отбор Цикл + ЭлементОтбора.Установить(Запись[ЭлементОтбора.Имя]); + КонецЦикла; + +КонецПроцедуры + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТТестовыеДанныеСлужебныйТаблицыЗначений.xml b/src/cfe/YAXUnit/CommonModules/ЮТТестовыеДанныеСлужебныйТаблицыЗначений.xml new file mode 100644 index 0000000..df01bd3 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТТестовыеДанныеСлужебныйТаблицыЗначений.xml @@ -0,0 +1,23 @@ + + + + + ЮТТестовыеДанныеСлужебныйТаблицыЗначений + + + ru + Тестовые данные таблицы значений + + + + false + false + true + false + true + false + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТТестовыеДанныеСлужебныйТаблицыЗначений/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТТестовыеДанныеСлужебныйТаблицыЗначений/Ext/Module.bsl new file mode 100644 index 0000000..9269c0b --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТТестовыеДанныеСлужебныйТаблицыЗначений/Ext/Module.bsl @@ -0,0 +1,562 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область СлужебныйПрограммныйИнтерфейс + +Функция ЗагрузитьИзМакета(Макет, ОписанияТипов, КэшЗначений, ЗаменяемыеЗначения, ПараметрыЗаполнения) Экспорт + + ДанныеМакета = ДанныеМакета(Макет); + ТипДанныхМакета = ТипЗнч(ДанныеМакета); + + Если ТипДанныхМакета = Тип("ТабличныйДокумент") Тогда + Результат = ЗагрузитьДанныеИзТабличногоДокумента(ДанныеМакета, ОписанияТипов, ЗаменяемыеЗначения, КэшЗначений, ПараметрыЗаполнения); + ИначеЕсли ТипДанныхМакета = Тип("ТекстовыйДокумент") ИЛИ ТипДанныхМакета = Тип("Строка") Тогда + Результат = ЗагрузитьДанныеИзСтроки(ДанныеМакета, ОписанияТипов, ЗаменяемыеЗначения, КэшЗначений, ПараметрыЗаполнения); + Иначе + ВызватьИсключение "Макет должен быть либо табличным, либо текстовым документом"; + КонецЕсли; + + Возврат Результат; + +КонецФункции + +#КонецОбласти + +#Область СлужебныеПроцедурыИФункции + +Функция ЗагрузитьДанныеИзТабличногоДокумента(ДанныеМакета, ОписанияТипов, ЗаменяемыеЗначения, КэшЗначений, ПараметрыЗаполнения) + + КолонкиМакета = Новый Массив(); + Для Инд = 1 По ДанныеМакета.ШиринаТаблицы Цикл + ИмяКолонки = ДанныеМакета.Область(1, Инд).Текст; + КолонкиМакета.Добавить(ИмяКолонки); + КонецЦикла; + + ПараметрыЗагрузки = ПараметрыЗагрузки(КолонкиМакета, ОписанияТипов, ЗаменяемыеЗначения, КэшЗначений, ПараметрыЗаполнения); + + Выборка = ЮТОбщийСлужебныйВызовСервера.ВыборкаИзТабличногоДокумента(ДанныеМакета); + + Пока Выборка.Следующий() Цикл + + Строка = ПараметрыЗагрузки.Таблица.Добавить(); + + Для Каждого ОписаниеКолонки Из ПараметрыЗагрузки.ОписаниеКолонок Цикл + + ЗначениеПредставления = Выборка[ОписаниеКолонки.Индекс]; + + Если ПустаяСтрока(ЗначениеПредставления) Тогда + Продолжить; + КонецЕсли; + + Значение = ЗначениеЯчейки(Выборка, + ЗначениеПредставления, + ОписаниеКолонки, + ЗаменяемыеЗначения, + КэшЗначений, + ПараметрыЗагрузки.ПараметрыСоздания); + Строка[ОписаниеКолонки.Имя] = Значение; + + КонецЦикла; + + КонецЦикла; + + Возврат ПараметрыЗагрузки.Таблица; + +КонецФункции + +Функция ЗагрузитьДанныеИзСтроки(ДанныеМакета, ОписанияТипов, ЗаменяемыеЗначения, КэшЗначений, ПараметрыЗаполнения) + + Разделитель = "|"; + ПараметрыИтератора = ПараметрыИтератора(ДанныеМакета); + + Пока СледующаяСтрока(ПараметрыИтератора) Цикл + + Строка = СокрЛП(ПараметрыИтератора.Строка); + + Если НЕ СтрНачинаетсяС(Строка, Разделитель) Тогда + Продолжить; + КонецЕсли; + + КолонкиМакета = ЮТСтроки.РазделитьСтроку(Строка, Разделитель); + + СледующаяСтрока(ПараметрыИтератора); + Прервать; + + КонецЦикла; + + ПараметрыЗагрузки = ПараметрыЗагрузки(КолонкиМакета, ОписанияТипов, ЗаменяемыеЗначения, КэшЗначений, ПараметрыЗаполнения); + + Пока СледующаяСтрока(ПараметрыИтератора) Цикл + + Строка = СокрЛП(ПараметрыИтератора.Строка); + + Если ПустаяСтрока(Строка) Тогда + Продолжить; + ИначеЕсли НЕ СтрНачинаетсяС(Строка, Разделитель) Тогда + Прервать; + КонецЕсли; + + СтрокаДанных = ПараметрыЗагрузки.Таблица.Добавить(); + Блоки = ЮТСтроки.РазделитьСтроку(Строка, Разделитель); + + Для Каждого ОписаниеКолонки Из ПараметрыЗагрузки.ОписаниеКолонок Цикл + + ЗначениеПредставления = Блоки[ОписаниеКолонки.Индекс]; + + Если ПустаяСтрока(ЗначениеПредставления) Тогда + Продолжить; + КонецЕсли; + + Значение = ЗначениеЯчейки(Блоки, + ЗначениеПредставления, + ОписаниеКолонки, + ЗаменяемыеЗначения, + КэшЗначений, + ПараметрыЗагрузки.ПараметрыСоздания); + СтрокаДанных[ОписаниеКолонки.Имя] = Значение; + + КонецЦикла; + + КонецЦикла; + + Возврат ПараметрыЗагрузки.Таблица; + +КонецФункции + +Функция ПараметрыИтератора(Источник) + + ПараметрыЧтения = Новый Структура; + + ПараметрыЧтения.Вставить("ИзТекстовогоДокумента", Ложь); + ПараметрыЧтения.Вставить("ИзЧтенияТекста", Ложь); + ПараметрыЧтения.Вставить("ИзВыборки", Ложь); + ПараметрыЧтения.Вставить("ДостиглиКонца", Ложь); + ПараметрыЧтения.Вставить("Строка", Неопределено); + + ТипЗначения = ТипЗнч(Источник); + + Если ТипЗначения = Тип("ТекстовыйДокумент") Тогда + ПараметрыЧтения.ИзТекстовогоДокумента = Истина; + ПараметрыЧтения.Вставить("ТекстовыйДокумент", Источник); + ПараметрыЧтения.Вставить("КоличествоСтрок", Источник.КоличествоСтрок()); + ПараметрыЧтения.Вставить("ИндексСтроки", 0); + ИначеЕсли ТипЗначения = Тип("Строка") Тогда + ПараметрыЧтения.ИзЧтенияТекста = Истина; + Кодировка = КодировкаТекста.UTF8; + Поток = ПолучитьДвоичныеДанныеИзСтроки(Источник, Кодировка).ОткрытьПотокДляЧтения(); + Чтение = Новый ЧтениеТекста(Поток, Кодировка); + ПараметрыЧтения.Вставить("Чтение", Чтение); + ПараметрыЧтения.Вставить("Поток", Поток); + ИначеЕсли ТипЗначения = Тип("ВыборкаДанных") Тогда + ПараметрыЧтения.ИзВыборки = Истина; + ПараметрыЧтения.Вставить("Выборка", Источник); + Иначе + ВызватьИсключение ЮТИсключения.НекорректныеПараметрыМетода("ЗагрузитьИзМакета", "неподдерживаемый источник"); + КонецЕсли; + + Возврат ПараметрыЧтения; + +КонецФункции + +Функция СледующаяСтрока(ПараметрыЧтения) + + Если ПараметрыЧтения.ДостиглиКонца Тогда + ВызватьИсключение "Построчное чтение уже завершено. Обнаружена попытка чтения завершенного потока"; + КонецЕсли; + + Если ПараметрыЧтения.ИзТекстовогоДокумента Тогда + + ЮТОбщий.Инкремент(ПараметрыЧтения.ИндексСтроки); + Если ПараметрыЧтения.ИндексСтроки > ПараметрыЧтения.КоличествоСтрок Тогда + ПараметрыЧтения.ДостиглиКонца = Истина; + Возврат Ложь; + КонецЕсли; + ПараметрыЧтения.Строка = ПараметрыЧтения.ТекстовыйДокумент.ПолучитьСтроку(ПараметрыЧтения.ИндексСтроки); + + ИначеЕсли ПараметрыЧтения.ИзЧтенияТекста Тогда + + ПараметрыЧтения.Строка = ПараметрыЧтения.Чтение.ПрочитатьСтроку(); + + Если ПараметрыЧтения.Строка = Неопределено Тогда + ПараметрыЧтения.Чтение.Закрыть(); + ПараметрыЧтения.Поток.Закрыть(); + ПараметрыЧтения.ДостиглиКонца = Истина; + Возврат Ложь; + КонецЕсли; + + ИначеЕсли ПараметрыЧтения.ИзВыборки Тогда + + Если ПараметрыЧтения.Выборка.Следующий() Тогда + ПараметрыЧтения.Строка = ПараметрыЧтения.Выборка; + Иначе + ПараметрыЧтения.ДостиглиКонца = Истина; + ПараметрыЧтения.Строка = Неопределено; + Возврат Ложь; + КонецЕсли; + + Иначе + ВызватьИсключение ЮТИсключения.НекорректныеПараметрыМетода("ЗагрузитьИзМакета", "Некорректные/неподдерживаемые параметры чтения"); + + КонецЕсли; + + Возврат Истина; + +КонецФункции + +Функция ДанныеМакета(Знач Макет) + + ТипПараметра = ТипЗнч(Макет); + ДанныеМакета = Неопределено; + + ПараметрыСодержитДанные = ТипПараметра = Тип("ТабличныйДокумент") + ИЛИ ТипПараметра = Тип("ТекстовыйДокумент") + ИЛИ ТипПараметра = Тип("Строка") И СтрНачинаетсяС(Макет, "|"); + + Если ПараметрыСодержитДанные Тогда + ДанныеМакета = Макет; + ИначеЕсли ТипПараметра = Тип("Строка") Тогда + ДанныеМакета = ЮТОбщийСлужебныйВызовСервера.Макет(Макет); + Иначе + ВызватьИсключение ЮТИсключения.НеподдерживаемыйПараметрМетода("ЮТТестовыеДанныеВызовСервера.ДанныеМакета", Макет); + КонецЕсли; + + Возврат ДанныеМакета; + +КонецФункции + +Функция ЗначениеЯчейки(СтрокаДанных, ЗначениеПредставления, ОписаниеКолонки, ЗаменяемыеЗначения, КэшЗначений, ПараметрыСоздания) + + Значение = ЗаменяемыеЗначения[ЗначениеПредставления]; + + КэшироватьЗначение = Значение = Неопределено И ОписаниеКолонки.Менеджер <> Неопределено; + + Если КэшироватьЗначение Тогда + Если КэшЗначений[ОписаниеКолонки.КлючТипаЗначения] = Неопределено Тогда + КэшЗначений.Вставить(ОписаниеКолонки.КлючТипаЗначения, Новый Соответствие()); + Иначе + Значение = КэшЗначений[ОписаниеКолонки.КлючТипаЗначения][ЗначениеПредставления]; + КонецЕсли; + КонецЕсли; + + Если Значение <> Неопределено Тогда + Возврат Значение; + КонецЕсли; + + ЗначенияРеквизитов = ЗначенияРеквизитов(СтрокаДанных, ОписаниеКолонки, ЗаменяемыеЗначения, КэшЗначений, ПараметрыСоздания); + Значение = ПривестиЗначениеКолонки(ОписаниеКолонки, ЗначениеПредставления, ЗначенияРеквизитов, ПараметрыСоздания); + + Если КэшироватьЗначение Тогда + КэшЗначений[ОписаниеКолонки.КлючТипаЗначения].Вставить(ЗначениеПредставления, Значение); + КонецЕсли; + + Возврат Значение; + +КонецФункции + +Процедура ПодготовитьПараметрыЗаполненияТаблицы(КэшЗначений, ЗаменяемыеЗначения, ПараметрыЗаполнения, Колонки) + + Если ЗаменяемыеЗначения = Неопределено Тогда + ЗаменяемыеЗначения = Новый Соответствие; + КонецЕсли; + + Если НЕ ЗначениеЗаполнено(КэшЗначений) Тогда + КэшЗначений = Новый Соответствие; + КонецЕсли; + + Для Каждого Колонка Из Колонки Цикл + + Если НЕ Колонка.Ссылочный Тогда + Продолжить; + КонецЕсли; + + Если КэшЗначений[Колонка.КлючТипаЗначения] = Неопределено Тогда + КэшЗначений.Вставить(Колонка.КлючТипаЗначения, Новый Соответствие); + КонецЕсли; + + КонецЦикла; + +КонецПроцедуры + +Функция ЗначенияРеквизитов(СтрокаТаблицы, ОписаниеКолонки, ЗаменяемыеЗначения, КэшЗначений, Параметры) + + ЗначенияРеквизитов = Новый Структура(); + + Для Каждого ОписаниеВложеннойКолонки Из ОписаниеКолонки.ДополнительныеРеквизиты Цикл + + ПредставлениеЗначения = СтрокаТаблицы[ОписаниеВложеннойКолонки.Индекс]; + Если ПустаяСтрока(ПредставлениеЗначения) Тогда + Продолжить; + КонецЕсли; + + Значение = ЗначениеЯчейки(СтрокаТаблицы, ПредставлениеЗначения, ОписаниеВложеннойКолонки, ЗаменяемыеЗначения, КэшЗначений, Параметры); + ЗначенияРеквизитов.Вставить(ОписаниеВложеннойКолонки.Имя, Значение); + + КонецЦикла; + + ОписаниеОбъектаМетаданных = ОписаниеКолонки.ОписаниеОбъектаМетаданных; + + Если ОписаниеОбъектаМетаданных <> Неопределено И ОписаниеОбъектаМетаданных.ОписаниеТипа.Имя = "Справочник" Тогда + ИмяРеквизита = "Наименование"; + Если ОписаниеОбъектаМетаданных.Реквизиты.Свойство(ИмяРеквизита) = Неопределено Тогда + ИмяРеквизита = "Код"; + КонецЕсли; + ЗначенияРеквизитов.Вставить(ИмяРеквизита, СтрокаТаблицы[ОписаниеКолонки.Индекс]); + КонецЕсли; + + Возврат ЗначенияРеквизитов; + +КонецФункции + +Функция ПривестиЗначениеКолонки(ОписаниеКолонки, ЗначениеПредставления, ЗначенияРеквизитов, ПараметрыЗаписи) + + Если ОписаниеКолонки.ЭтоПеречисление Тогда + Значение = ОписаниеКолонки.Менеджер[ЗначениеПредставления]; + ИначеЕсли ОписаниеКолонки.Ссылочный Тогда + Значение = СоздатьНовуюЗапись(ОписаниеКолонки, ЗначенияРеквизитов, ПараметрыЗаписи); + ИначеЕсли ОписаниеКолонки.ЭтоДата Тогда + Значение = ЮТПреобразованияСлужебный.ПривестиЗначениеКДате(ОписаниеКолонки.ОписаниеТипа, ЗначениеПредставления); + ИначеЕсли ОписаниеКолонки.ЭтоЧисло Тогда + Значение = ЮТПреобразованияСлужебный.ПривестиЗначениеКЧислу(ОписаниеКолонки.ОписаниеТипа, ЗначениеПредставления); + Иначе + Значение = ОписаниеКолонки.ОписаниеТипа.ПривестиЗначение(ЗначениеПредставления); + КонецЕсли; + + Возврат Значение; + +КонецФункции + +Функция СоздатьНовуюЗапись(ОписаниеКолонки, ЗначенияРеквизитов, ПараметрыЗаписи) + + Конструктор = ЮТТестовыеДанные.КонструкторОбъекта(ОписаниеКолонки.Менеджер); + + Если ЗначениеЗаполнено(ЗначенияРеквизитов) Тогда + Для Каждого ДанныеЗначения Из ЗначенияРеквизитов Цикл + Конструктор.Установить(ДанныеЗначения.Ключ, ДанныеЗначения.Значение); + КонецЦикла; + КонецЕсли; + + Если ПараметрыЗаписи.ФикцияОбязательныхПолей Тогда + Конструктор.ФикцияОбязательныхПолей(); + КонецЕсли; + + Возврат Конструктор.Записать( , ПараметрыЗаписи.ПараметрыЗаписи.ОбменДаннымиЗагрузка); + +КонецФункции + +Функция НоваяТаблица(ОписаниеКолонок) + + ТаблицаЗначений = Новый ТаблицаЗначений(); + + Для Каждого ОписаниеКолонки Из ОписаниеКолонок Цикл + ТаблицаЗначений.Колонки.Добавить(ОписаниеКолонки.Имя, ОписаниеКолонки.ОписаниеТипа); + КонецЦикла; + + Возврат ТаблицаЗначений; + +КонецФункции + +Функция ПараметрыЗагрузки(КолонкиМакета, ОписанияТипов, ЗаменяемыеЗначения, КэшЗначений, ПараметрыЗаполнения) + + ОписаниеКолонок = ОписаниеКолонок(КолонкиМакета, ОписанияТипов); + ПодготовитьПараметрыЗаполненияТаблицы(КэшЗначений, ЗаменяемыеЗначения, ПараметрыЗаполнения, ОписаниеКолонок); + ПараметрыСоздания = ПараметрыЗаполнения.СозданиеОбъектовМетаданных; + + ТаблицаЗначений = НоваяТаблица(ОписаниеКолонок); + + ПараметрыЗагрузки = Новый Структура; + + ПараметрыЗагрузки.Вставить("ОписаниеКолонок", ОписаниеКолонок); + ПараметрыЗагрузки.Вставить("ПараметрыСоздания", ПараметрыСоздания); + ПараметрыЗагрузки.Вставить("Таблица", ТаблицаЗначений); + + Возврат ПараметрыЗагрузки; + +КонецФункции + +#Область ОписаниеКолонок + +Функция ОписаниеКолонок(КолонкиМакета, ОписанияТипов) + + ОсновныеКолонки = ОсновныеКолонкиМакета(КолонкиМакета); + + Для Каждого Элемент Из ОписанияТипов Цикл + + Если НЕ ОсновныеКолонки.Свойство(Элемент.Ключ) Тогда + + Сообщение = СтрШаблон("Макет не содержит колонку `%1`", Элемент.Ключ); + ВызватьИсключение Сообщение; + + КонецЕсли; + + КонецЦикла; + + Если ТипЗнч(ОписанияТипов) = Тип("Структура") Тогда + ОписанияТипов = ЮТКоллекции.ВСоответствие(ОписанияТипов, "Ключ", "Значение"); + КонецЕсли; + + ЗагружаемыеКолонки = Новый Массив(); + + Для Каждого Элемент Из ОсновныеКолонки Цикл + + ОписаниеТиповКолонки = ОписанияТипов[Элемент.Ключ]; + + Если ОписаниеТиповКолонки = Неопределено Тогда + Продолжить; + КонецЕсли; + + ОсновнаяКолонка = Элемент.Значение; + ЗагружаемыеКолонки.Добавить(ОсновнаяКолонка); + + ОсновнаяКолонка.ОписаниеТипа = ОписаниеТиповКолонки; + ДозаполнитьОписаниеКолонки(ОсновнаяКолонка); + + ДополнительныеКолонки = ОсновнаяКолонка.ДополнительныеРеквизиты; + ОсновнаяКолонка.ДополнительныеРеквизиты = Новый Массив(); + + Для Каждого ВложеннаяКолонка Из ДополнительныеКолонки Цикл + + ВложеннаяКолонка.ОписаниеТипа = ОписаниеТипаВложеннойКолонки(ОписанияТипов, ОсновнаяКолонка, ВложеннаяКолонка); + + Если ВложеннаяКолонка.ОписаниеТипа = Неопределено Тогда + Продолжить; + КонецЕсли; + + ОсновнаяКолонка.ДополнительныеРеквизиты.Добавить(ВложеннаяКолонка); + ДозаполнитьОписаниеКолонки(ВложеннаяКолонка); + + КонецЦикла; + + ОсновнаяКолонка.Составное = ЗначениеЗаполнено(ОсновнаяКолонка.ДополнительныеРеквизиты); + + КонецЦикла; + + Возврат ЗагружаемыеКолонки; + +КонецФункции + +Функция ОписаниеТипаВложеннойКолонки(ОписанияТипов, ОсновнаяКолонка, ВложеннаяКолонка) + + ПолноеИмя = СтрШаблон("%1.%2", ОсновнаяКолонка.Имя, ВложеннаяКолонка.Имя); + ОписаниеТипа = ОписанияТипов[ПолноеИмя]; + + Если ОписаниеТипа = Неопределено Тогда + Реквизиты = ОсновнаяКолонка.ОписаниеОбъектаМетаданных.Реквизиты; + + Если Реквизиты.Свойство(ВложеннаяКолонка.Имя) Тогда + ОписаниеТипа = Реквизиты[ВложеннаяКолонка.Имя].Тип; + КонецЕсли; + КонецЕсли; + + Возврат ОписаниеТипа; + +КонецФункции + +Функция ОписаниеКолонки(Индекс) + + ОписаниеКолонки = Новый Структура; + ОписаниеКолонки.Вставить("Индекс", Индекс); + ОписаниеКолонки.Вставить("Имя", ""); + + ОписаниеКолонки.Вставить("ОписаниеТипа", Неопределено); + ОписаниеКолонки.Вставить("ТипЗначения", Неопределено); + ОписаниеКолонки.Вставить("Ссылочный", Ложь); + ОписаниеКолонки.Вставить("ДополнительныеРеквизиты", Новый Массив()); + ОписаниеКолонки.Вставить("Составное", Ложь); + ОписаниеКолонки.Вставить("Менеджер", Неопределено); + ОписаниеКолонки.Вставить("КлючТипаЗначения", Неопределено); + ОписаниеКолонки.Вставить("ОписаниеОбъектаМетаданных", Неопределено); + ОписаниеКолонки.Вставить("ЭтоПеречисление", Ложь); + ОписаниеКолонки.Вставить("ЭтоЧисло", Ложь); + ОписаниеКолонки.Вставить("ЭтоДата", Ложь); + + Возврат ОписаниеКолонки; + +КонецФункции + +Функция ОсновныеКолонкиМакета(КолонкиМакета) + + ОсновныеКолонки = Новый Структура(); + + ВторойУровеньВложенности = 2; + + // Сначала соберем основные колонки + Для Инд = 0 По КолонкиМакета.ВГраница() Цикл + + ИмяКолонки = КолонкиМакета[Инд]; + ЧастиИмени = СтрРазделить(ИмяКолонки, "."); + + Если ПустаяСтрока(ИмяКолонки) ИЛИ ЧастиИмени.Количество() = ВторойУровеньВложенности Тогда + Продолжить; + ИначеЕсли ЧастиИмени.Количество() > ВторойУровеньВложенности Тогда + Сообщение = СтрШаблон("Некорректное имя колонки макета `%1`, доступно использовать максимум 1 уровень вложенности", ИмяКолонки); + ВызватьИсключение Сообщение; + Иначе + ОписаниеКолонки = ОписаниеКолонки(Инд); + ОписаниеКолонки.Имя = ИмяКолонки; + + ОсновныеКолонки.Вставить(ИмяКолонки, ОписаниеКолонки); + КонецЕсли; + + КонецЦикла; + + Для Инд = 0 По КолонкиМакета.ВГраница() Цикл + + ЧастиИмени = СтрРазделить(КолонкиМакета[Инд], "."); + + Если ЧастиИмени.Количество() <> ВторойУровеньВложенности Тогда + Продолжить; + КонецЕсли; + + Если НЕ ОсновныеКолонки.Свойство(ЧастиИмени[0]) Тогда + Сообщение = СтрШаблон("Для колонки `%1` не найдена в макете основная колонка с именем `%2`", ИмяКолонки, ЧастиИмени[0]); + ВызватьИсключение Сообщение; + КонецЕсли; + + ОсновнаяКолонка = ОсновныеКолонки[ЧастиИмени[0]]; + ОписаниеКолонки = ОписаниеКолонки(Инд); + ОписаниеКолонки.Имя = ЧастиИмени[1]; + + ОсновнаяКолонка.ДополнительныеРеквизиты.Добавить(ОписаниеКолонки); + + КонецЦикла; + + Возврат ОсновныеКолонки; + +КонецФункции + +Процедура ДозаполнитьОписаниеКолонки(ОписаниеКолонки) + + ТипЗначения = ОписаниеКолонки.ОписаниеТипа.Типы()[0]; + ОписаниеКолонки.ТипЗначения = ТипЗначения; + + ОписаниеКолонки.Ссылочный = ЮТТипыДанныхСлужебный.ЭтоСсылочныйТип(ТипЗначения); + ОписаниеКолонки.ЭтоЧисло = ТипЗначения = Тип("Число"); + ОписаниеКолонки.ЭтоДата = ТипЗначения = Тип("Дата"); + + Если ОписаниеКолонки.Ссылочный Тогда + ОписаниеКолонки.ОписаниеОбъектаМетаданных = ЮТМетаданные.ОписаниеОбъектаМетаданных(ТипЗначения); + ОписаниеКолонки.ЭтоПеречисление = ЮТМетаданные.ЭтоПеречисление(ОписаниеКолонки.ОписаниеОбъектаМетаданных); + ОписаниеКолонки.Менеджер = ЮТОбщий.Менеджер(ОписаниеКолонки.ОписаниеОбъектаМетаданных); + ОписаниеКолонки.КлючТипаЗначения = ЮТТипыДанныхСлужебный.ИдентификаторТипа(ТипЗначения); + КонецЕсли; + +КонецПроцедуры + +#КонецОбласти + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТТесты.xml b/src/cfe/YAXUnit/CommonModules/ЮТТесты.xml new file mode 100644 index 0000000..e687646 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТТесты.xml @@ -0,0 +1,23 @@ + + + + + ЮТТесты + + + ru + Регистрация тестов + + + + false + true + true + false + true + false + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТТесты/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТТесты/Ext/Module.bsl new file mode 100644 index 0000000..4ab119a --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТТесты/Ext/Module.bsl @@ -0,0 +1,353 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +///////////////////////////////////////////////////////////////////////////////// +// Содержит методы создания тестов и тестовых наборов +///////////////////////////////////////////////////////////////////////////////// + +#Область ПрограммныйИнтерфейс + +// Создает и регистрирует тестовый набор, в который будут добавляться последующие тесты +// Параметры: +// Имя - Строка - Имя набора тестов +// ТегиСтрокой - Строка - Теги относящиеся к набору и вложенным тестам. Это строка разделенная запятыми +// +// Возвращаемое значение: +// ОбщийМодуль - Этот же модуль +Функция ДобавитьТестовыйНабор(Имя, ТегиСтрокой = "") Экспорт + + ЮТТестыСлужебный.ДобавитьТестовыйНабор(Имя, ТегиСтрокой); + + Возврат ЮТТесты; + +КонецФункции + +// Регистрирует тест, исполняемый в контекстах, в которых доступен тестовый модуль. +// Например +// +// * Если модуль с тестами клиент-серверный, то тест будет вызван и на клиенте и на сервере. +// * Если клиентский, то только на клиенте. +// * Если клиент обычное приложение, то только при запуске в режиме обычного приложения. +// +// Параметры: +// ИмяТестовогоМетода - Строка - Имя тестового метода +// ПредставлениеТеста - Строка - Представление теста +// ТегиСтрокой - Строка - Теги строкой. Это строка разделенная запятыми +// Контексты - Строка - Контексты, строка перечисления контекстов вызова, разделенных запятой. +// Возможные значения см. ЮТФабрика.КонтекстыВызова +// Возвращаемое значение: +// ОбщийМодуль - Этот же модуль +Функция ДобавитьТест(ИмяТестовогоМетода, ПредставлениеТеста = "", ТегиСтрокой = "", Контексты = Неопределено) Экспорт + + ЮТТестыСлужебный.ДобавитьТест(ИмяТестовогоМетода, ПредставлениеТеста, ТегиСтрокой, Контексты); + + Возврат ЮТТесты; + +КонецФункции + +// Регистрирует тест исполняемый на клиенте. +// +// Параметры: +// ИмяТестовогоМетода - Строка - Имя тестового метода +// ПредставлениеТеста - Строка - Представление теста +// ТегиСтрокой - Строка - Теги строкой. Это строка разделенная запятыми +// +// Возвращаемое значение: +// ОбщийМодуль - Этот же модуль +Функция ДобавитьКлиентскийТест(ИмяТестовогоМетода, ПредставлениеТеста = "", ТегиСтрокой = "") Экспорт + + ЮТТестыСлужебный.ДобавитьТест(ИмяТестовогоМетода, ПредставлениеТеста, ТегиСтрокой, ЮТТестыСлужебный.КонтекстыВызоваКлиента()); + + Возврат ЮТТесты; + +КонецФункции + +// Регистрирует тест исполняемый на сервере. +// +// Параметры: +// ИмяТестовогоМетода - Строка - Имя тестового метода +// ПредставлениеТеста - Строка - Представление теста +// ТегиСтрокой - Строка - Теги строкой. Это строка разделенная запятыми +// +// Возвращаемое значение: +// ОбщийМодуль - Этот же модуль +Функция ДобавитьСерверныйТест(ИмяТестовогоМетода, ПредставлениеТеста = "", ТегиСтрокой = "") Экспорт + + КонтекстыВызова = ЮТФабрика.КонтекстыВызова(); + ЮТТестыСлужебный.ДобавитьТест(ИмяТестовогоМетода, ПредставлениеТеста, ТегиСтрокой, КонтекстыВызова.Сервер); + + Возврат ЮТТесты; + +КонецФункции + +// Устанавливает настройку выполнения тестового метода. +// +// Параметры: +// ИмяПараметра - Строка +// Значение - Произвольный - Значение настройки +// +// Возвращаемое значение: +// ОбщийМодуль - Этот же модуль +Функция НастройкаИсполнения(ИмяПараметра, Значение) Экспорт + + ЮТТестыСлужебный.НастройкаИсполнения(ИмяПараметра, Значение); + + Возврат ЮТТесты; + +КонецФункции + +// Устанавливает настройку выполнения тестового метода в транзакции. +// +// Параметры: +// ВыполнятьВТранзакции - Булево +// +// Возвращаемое значение: +// ОбщийМодуль - Этот же модуль +Функция ВТранзакции(ВыполнятьВТранзакции = Истина) Экспорт + + ЮТТестыСлужебный.НастройкаИсполнения(ЮТФабрика.ПараметрыИсполненияТеста().ВТранзакции, ВыполнятьВТранзакции); + + Возврат ЮТТесты; + +КонецФункции + +// Устанавливает настройку удаления созданных тестовых данных +// В отличии от использования транзакции: +// +// * Умеет работать с данными созданными на клиенте +// * Только удаляет созданные данные и не откатывает изменения объектов +// * Работает с данными созданными через API работы с тестовыми данными +// * Удаляет данные созданные вне теста (в обработчиках событий, например, ПередВсемиТестами и ПередТестовымНабором) +// +// Параметры: +// УдалятьСозданныеДанные - Булево +// +// Возвращаемое значение: +// ОбщийМодуль - Этот же модуль +Функция УдалениеТестовыхДанных(УдалятьСозданныеДанные = Истина) Экспорт + + ЮТТестыСлужебный.НастройкаИсполнения(ЮТФабрика.ПараметрыИсполненияТеста().УдалениеТестовыхДанных, УдалятьСозданныеДанные); + + Возврат ЮТТесты; + +КонецФункции + +// Устанавливает настройку переопределения обработчика события Перед... +// +// Параметры: +// ВыполнитьПеред - Строка - Имя обработчика события, который будет выполнен вместо основного +// +// Возвращаемое значение: +// ОбщийМодуль - Этот же модуль +Функция Перед(ВыполнитьПеред = "") Экспорт + + ЮТТестыСлужебный.НастройкаИсполнения(ЮТФабрика.ПараметрыИсполненияТеста().Перед, ВыполнитьПеред); + + Возврат ЮТТесты; + +КонецФункции + +// Устанавливает настройку переопределения обработчика события После... +// +// Параметры: +// ВыполнитьПосле - Строка - Имя обработчика события, который будет выполнен вместо основного +// +// Возвращаемое значение: +// ОбщийМодуль - Этот же модуль +Функция После(ВыполнитьПосле = "") Экспорт + + ЮТТестыСлужебный.НастройкаИсполнения(ЮТФабрика.ПараметрыИсполненияТеста().После, ВыполнитьПосле); + + Возврат ЮТТесты; + +КонецФункции + +// Устанавливает параметры вызова теста. +// +// * Если метод вызывается первый раз, то он устанавливает параметры теста. +// * Если второй и последующие, то добавляет новый тест с параметрами. +// +// Параметры: +// Параметр1 - Произвольный +// Параметр2 - Произвольный +// Параметр3 - Произвольный +// Параметр4 - Произвольный +// Параметр5 - Произвольный +// Параметр6 - Произвольный +// Параметр7 - Произвольный +// Параметр8 - Произвольный +// Параметр9 - Произвольный +// Параметр10 - Произвольный +// +// Возвращаемое значение: +// ОбщийМодуль - Этот же модуль +// +// Примеры: +// +// ЮТТесты.ДобавитьТест("Тест1").СПараметрами(1, 2); // Будет зарегистрирован один тест с параметрами 1, 2 +// ЮТТесты.ДобавитьТест("Тест1") +// .СПараметрами(1) +// .СПараметрами(2); // Будет зарегистрировано два теста, первый с параметром 1 и второй с параметром 2 +// +//@skip-check method-too-many-params +Функция СПараметрами(Параметр1 = "_!%*", + Параметр2 = "_!%*", + Параметр3 = "_!%*", + Параметр4 = "_!%*", + Параметр5 = "_!%*", + Параметр6 = "_!%*", + Параметр7 = "_!%*", + Параметр8 = "_!%*", + Параметр9 = "_!%*", + Параметр10 = "_!%*") Экспорт + + Параметры = ЮТКоллекции.ЗначениеВМассиве(Параметр1, + Параметр2, + Параметр3, + Параметр4, + Параметр5, + Параметр6, + Параметр7, + Параметр8, + Параметр9, + Параметр10); + + ЮТТестыСлужебный.СПараметрами(Параметры, Неопределено); + + Возврат ЮТТесты; + +КонецФункции + +// Устанавливает параметры вызова теста и новый контекст исполнения (клиентский). +// +// * Если метод вызывается первый раз, то он устанавливает параметры теста. +// * Если второй и последующие, то добавляет новый тест с параметрами. +// +// Параметры: +// Параметр1 - Произвольный +// Параметр2 - Произвольный +// Параметр3 - Произвольный +// Параметр4 - Произвольный +// Параметр5 - Произвольный +// Параметр6 - Произвольный +// Параметр7 - Произвольный +// Параметр8 - Произвольный +// Параметр9 - Произвольный +// Параметр10 - Произвольный +// +// Возвращаемое значение: +// ОбщийМодуль - Этот же модуль +// +//@skip-check method-too-many-params +Функция СПараметрамиНаКлиенте(Параметр1 = "_!%*", + Параметр2 = "_!%*", + Параметр3 = "_!%*", + Параметр4 = "_!%*", + Параметр5 = "_!%*", + Параметр6 = "_!%*", + Параметр7 = "_!%*", + Параметр8 = "_!%*", + Параметр9 = "_!%*", + Параметр10 = "_!%*") Экспорт + + Параметры = ЮТКоллекции.ЗначениеВМассиве(Параметр1, + Параметр2, + Параметр3, + Параметр4, + Параметр5, + Параметр6, + Параметр7, + Параметр8, + Параметр9, + Параметр10); + + ЮТТестыСлужебный.СПараметрами(Параметры, ЮТТестыСлужебный.КонтекстыВызоваКлиента()); + + Возврат ЮТТесты; + +КонецФункции + +// Устанавливает параметры вызова теста и новый контекст исполнения (серверный). +// +// * Если метод вызывается первый раз, то он устанавливает параметры теста. +// * Если второй и последующие, то добавляет новый тест с параметрами. +// +// Параметры: +// Параметр1 - Произвольный +// Параметр2 - Произвольный +// Параметр3 - Произвольный +// Параметр4 - Произвольный +// Параметр5 - Произвольный +// Параметр6 - Произвольный +// Параметр7 - Произвольный +// Параметр8 - Произвольный +// Параметр9 - Произвольный +// Параметр10 - Произвольный +// +// Возвращаемое значение: +// ОбщийМодуль - Этот же модуль +// +//@skip-check method-too-many-params +Функция СПараметрамиНаСервере(Параметр1 = "_!%*", + Параметр2 = "_!%*", + Параметр3 = "_!%*", + Параметр4 = "_!%*", + Параметр5 = "_!%*", + Параметр6 = "_!%*", + Параметр7 = "_!%*", + Параметр8 = "_!%*", + Параметр9 = "_!%*", + Параметр10 = "_!%*") Экспорт + + Параметры = ЮТКоллекции.ЗначениеВМассиве(Параметр1, + Параметр2, + Параметр3, + Параметр4, + Параметр5, + Параметр6, + Параметр7, + Параметр8, + Параметр9, + Параметр10); + + КонтекстыВызова = ЮТФабрика.КонтекстыВызова(); + ЮТТестыСлужебный.СПараметрами(Параметры, КонтекстыВызова.Сервер); + + Возврат ЮТТесты; + +КонецФункции + +// Устанавливает представление объекта, может использоваться как для теста, так и для набора. +// +// Параметры: +// Представление - Строка +// ИспользуяИмя - Булево - Необходимо ли использовать имя объекта при формировании представления. +// Ложь - По умолчанию, представление будет установлено по параметру. +// Истина - Новое представление объекта = `<ИмяОбъект>. <Параметр Представление>` +// +// Возвращаемое значение: +// ОбщийМодуль - Этот же модуль +Функция Представление(Представление, ИспользуяИмя = Ложь) Экспорт + + ЮТТестыСлужебный.УстановитьПредставление(Представление, ИспользуяИмя); + + Возврат ЮТТесты; + +КонецФункции + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТТестыСлужебный.xml b/src/cfe/YAXUnit/CommonModules/ЮТТестыСлужебный.xml new file mode 100644 index 0000000..e0c7995 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТТестыСлужебный.xml @@ -0,0 +1,23 @@ + + + + + ЮТТестыСлужебный + + + ru + Тесты служебный + + + + false + true + true + false + true + false + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТТестыСлужебный/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТТестыСлужебный/Ext/Module.bsl new file mode 100644 index 0000000..c42d9c7 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТТестыСлужебный/Ext/Module.bsl @@ -0,0 +1,287 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область СлужебныйПрограммныйИнтерфейс + +Процедура ДобавитьТестовыйНабор(Имя, ТегиСтрокой) Экспорт + + ИсполняемыеСценарии = СценарииМодуля(); + + Если НЕ ЭтоИсполняемыеСценарии(ИсполняемыеСценарии) Тогда + ВызватьИсключение "Первый параметр должен быть результатом метода ЮТТесты.ИсполняемыеСценарии"; + КонецЕсли; + + Если ПустаяСтрока(Имя) Тогда + ВызватьИсключение "Имя тестового набора не может быть пустым"; + КонецЕсли; + + Контекст = Контекст(); + НовыйТестовыйНабор = ЮТФабрикаСлужебный.ОписаниеТестовогоНабора(Имя, ТегиСтрокой); + + ИсполняемыеСценарии.ТестовыеНаборы.Добавить(НовыйТестовыйНабор); + Контекст.ТекущийНабор = НовыйТестовыйНабор; + Контекст.ТекущийЭлемент = НовыйТестовыйНабор; + +КонецПроцедуры + +Процедура ДобавитьТест(ИмяТестовогоМетода, ПредставлениеТеста, ТегиСтрокой, Контексты) Экспорт + + Контекст = Контекст(); + Набор = Контекст.ТекущийНабор; + + ЭтоИсполняемыеСценарии = ЭтоИсполняемыеСценарии(Набор); + ЭтоТестовыйНабор = ЭтоТестовыйНабор(Набор); + + Если НЕ (ЭтоИсполняемыеСценарии ИЛИ ЭтоТестовыйНабор) Тогда + ВызватьИсключение "Первый параметр должен быть результатом метода ЮТТесты.ИсполняемыеСценарии или ЮТТесты.ТестовыйНабор"; + КонецЕсли; + + Если ПустаяСтрока(ИмяТестовогоМетода) Тогда + ВызватьИсключение "Имя тестового метода не может быть пустым"; + КонецЕсли; + + Тест = ОписаниеТеста(ИмяТестовогоМетода, ПредставлениеТеста, ТегиСтрокой, Контексты); + ДобавитьТестВНабор(Контекст, Тест, Ложь); + +КонецПроцедуры + +Процедура ДобавитьКлиентскийТест(ИмяТестовогоМетода, ПредставлениеТеста, ТегиСтрокой) Экспорт + + ДобавитьТест(ИмяТестовогоМетода, ПредставлениеТеста, ТегиСтрокой, КонтекстыВызоваКлиента()); + +КонецПроцедуры + +Процедура ДобавитьСерверныйТест(ИмяТестовогоМетода, ПредставлениеТеста, ТегиСтрокой) Экспорт + + Режимы = ЮТФабрика.КонтекстыВызова(); + + ДобавитьТест(ИмяТестовогоМетода, ПредставлениеТеста, ТегиСтрокой, Режимы.Сервер); + +КонецПроцедуры + +Процедура НастройкаИсполнения(ИмяПараметра, Значение) Экспорт + + Контекст = Контекст(); + + Если Контекст.ТекущийЭлемент = Неопределено Тогда + ВызватьИсключение "Не инициализированы настройки регистрации тестов"; + КонецЕсли; + + Контекст.ТекущийЭлемент.НастройкиВыполнения.Вставить(ИмяПараметра, Значение); + +КонецПроцедуры + +Процедура СПараметрами(Параметры, Знач НовыеКонтексты) Экспорт + + Контекст = Контекст(); + + Если Контекст.ТекущийЭлемент = Неопределено Тогда + ВызватьИсключение "Не инициализированы настройки регистрации тестов"; + ИначеЕсли НЕ ЭтоОписаниеТеста(Контекст.ТекущийЭлемент) Тогда + ВызватьИсключение "Параметры устанавливаются только для теста"; + КонецЕсли; + + ЭтоПервыйВызовСПараметрами = Контекст.ТекущийЭлемент.Параметры = Неопределено; + УстановитьНовыйКонтекст = ЗначениеЗаполнено(НовыеКонтексты); + + Если ЭтоПервыйВызовСПараметрами Тогда + Контекст.БазовыйТест = ЮТКоллекции.СкопироватьСтруктуру(Контекст.ТекущийЭлемент); + КонецЕсли; + + Если УстановитьНовыйКонтекст Тогда + НормализованныеКонтексты = НормализованныеКонтексты(НовыеКонтексты); + НовыеКонтексты = ЮТКоллекции.ПересечениеМассивов(Контекст.БазовыйТест.КонтекстВызова, НормализованныеКонтексты); + + Если НЕ ЗначениеЗаполнено(НовыеКонтексты) Тогда + ВызватьИсключение СтрШаблон("Не пересекаются контексты базового теста %1 и устанавливаемые %2", + ЮТКоллекции.ПредставлениеМассива(Контекст.БазовыйТест.КонтекстВызова), + ЮТКоллекции.ПредставлениеМассива(НормализованныеКонтексты)); + КонецЕсли; + КонецЕсли; + + Если НЕ ЭтоПервыйВызовСПараметрами Тогда + НоваяНастройка = ЮТКоллекции.СкопироватьСтруктуру(Контекст.БазовыйТест); + ДобавитьТестВНабор(Контекст, НоваяНастройка, Истина); + КонецЕсли; + + Контекст.ТекущийЭлемент.Параметры = Параметры; + + Если УстановитьНовыйКонтекст Тогда + Контекст.ТекущийЭлемент.КонтекстВызова = НовыеКонтексты; + КонецЕсли; + +КонецПроцедуры + +Процедура УстановитьПредставление(Представление, ИспользуяИмя) Экспорт + + ТекущийЭлемент = Контекст().ТекущийЭлемент; + Если ИспользуяИмя Тогда + ТекущийЭлемент.Представление = СтрШаблон("%1. %2", ТекущийЭлемент.Имя, Представление); + Иначе + ТекущийЭлемент.Представление = Представление; + КонецЕсли; + +КонецПроцедуры + +Функция КонтекстыВызоваКлиента() Экспорт + + Режимы = ЮТФабрика.КонтекстыВызова(); + Возврат ЮТКоллекции.ЗначениеВМассиве(Режимы.КлиентУправляемоеПриложение, Режимы.КлиентОбычноеПриложение); + +КонецФункции + +// Описание сценариев модуля +// +// Возвращаемое значение: +// Структура - см. ИсполняемыеСценарии +Функция СценарииМодуля() Экспорт + + Возврат Контекст().ИсполняемыеСценарии; + +КонецФункции + +Функция Контекст() Экспорт + + Возврат ЮТКонтекстСлужебный.ЗначениеКонтекста("КонтекстРегистрацияТестов"); + +КонецФункции + +#Область ОбработчикиСобытий + +Процедура ПередЧтениемСценариевМодуля(МетаданныеМодуля) Экспорт + + ИнициализироватьКонтекст(МетаданныеМодуля); + ЮТСобытияСлужебный.ПередЧтениемСценариевМодуля(МетаданныеМодуля); + +КонецПроцедуры + +Процедура ПослеЧтенияСценариевМодуля() Экспорт + + Контекст = Контекст(); + ЮТСобытияСлужебный.ПослеЧтенияСценариевМодуля(Контекст.МетаданныеМодуля, Контекст.ИсполняемыеСценарии); + +КонецПроцедуры + +#КонецОбласти + +#КонецОбласти + +#Область СлужебныеПроцедурыИФункции + +// Исполняемые сценарии. +// +// Параметры: +// МетаданныеМодуля - см. ЮТФабрикаСлужебный.ОписаниеМодуля +// +// Возвращаемое значение: +// Структура - Исполняемые сценарии: +// * ТестовыеНаборы - Массив из см. ЮТФабрикаСлужебный.ОписаниеТестовогоНабора - Тестовые наборы модуля +// * НастройкиВыполнения- Структура - Настройки исполнения теста +Функция ИсполняемыеСценарии(МетаданныеМодуля) + + Структура = Новый Структура; + Структура.Вставить("ТестовыеНаборы", Новый Массив()); + Структура.Вставить("НастройкиВыполнения", Новый Структура()); + + Набор = ЮТФабрикаСлужебный.ОписаниеТестовогоНабора(МетаданныеМодуля.Имя); + Набор.НастройкиВыполнения = Структура.НастройкиВыполнения; // Общие настройки с набором по умолчанию + Структура.ТестовыеНаборы.Добавить(Набор); + + Возврат Структура; + +КонецФункции + +Функция КонтекстыВызоваПоУмолчанию() + + Возврат ЮТФабрикаСлужебный.КонтекстыМодуля(Контекст().МетаданныеМодуля); + +КонецФункции + +Функция ОписаниеТеста(Имя, Знач Представление, ТегиСтрокой, Знач Контексты) + + Контексты = НормализованныеКонтексты(Контексты); + + Возврат ЮТФабрикаСлужебный.ОписаниеТеста(Имя, Представление, Контексты, ТегиСтрокой); + +КонецФункции + +Функция ЭтоИсполняемыеСценарии(ИсполняемыеСценарии) + + Возврат ТипЗнч(ИсполняемыеСценарии) = Тип("Структура") + И ТипЗнч(ЮТКоллекции.ЗначениеСтруктуры(ИсполняемыеСценарии, "ТестовыеНаборы")) = Тип("Массив"); + +КонецФункции + +Функция ЭтоТестовыйНабор(ТестовыйНабор) + + Возврат ТипЗнч(ТестовыйНабор) = Тип("Структура") + И ТипЗнч(ЮТКоллекции.ЗначениеСтруктуры(ТестовыйНабор, "Тесты")) = Тип("Массив"); + +КонецФункции + +Функция ЭтоОписаниеТеста(Описание) + + Возврат ТипЗнч(Описание) = Тип("Структура") + И ТипЗнч(ЮТКоллекции.ЗначениеСтруктуры(Описание, "КонтекстВызова")) = Тип("Массив"); + +КонецФункции + +Процедура ДобавитьТестВНабор(Контекст, Тест, ЭтоКопия) + + Если НЕ ЭтоКопия Тогда + Контекст.БазовыйТест = Неопределено; + КонецЕсли; + + Контекст.ТекущийНабор.Тесты.Добавить(Тест); + Контекст.ТекущийЭлемент = Тест; + Тест.НомерВНаборе = Контекст.ТекущийНабор.Тесты.Количество(); + +КонецПроцедуры + +Процедура ИнициализироватьКонтекст(МетаданныеМодуля) + + ИсполняемыеСценарии = ИсполняемыеСценарии(МетаданныеМодуля); + Набор = ИсполняемыеСценарии.ТестовыеНаборы[0]; + + Контекст = Новый Структура(); + + Контекст.Вставить("МетаданныеМодуля", МетаданныеМодуля); + Контекст.Вставить("ИсполняемыеСценарии", ИсполняемыеСценарии); + Контекст.Вставить("ТекущийНабор", Набор); + Контекст.Вставить("ТекущийЭлемент", Набор); + Контекст.Вставить("БазовыйТест", Неопределено); + + ЮТКонтекстСлужебный.УстановитьЗначениеКонтекста("КонтекстРегистрацияТестов", Контекст); + +КонецПроцедуры + +Функция НормализованныеКонтексты(ПараметрКонтексты) + + Если НЕ ЗначениеЗаполнено(ПараметрКонтексты) Тогда + Контексты = КонтекстыВызоваПоУмолчанию(); + ИначеЕсли ТипЗнч(ПараметрКонтексты) = Тип("Строка") Тогда + Контексты = СтрРазделить(ПараметрКонтексты, ", ", Ложь); + Иначе + Контексты = ПараметрКонтексты; + КонецЕсли; + + Возврат Контексты; + +КонецФункции + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТТипыДанныхСлужебный.xml b/src/cfe/YAXUnit/CommonModules/ЮТТипыДанныхСлужебный.xml new file mode 100644 index 0000000..b6cb6fa --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТТипыДанныхСлужебный.xml @@ -0,0 +1,23 @@ + + + + + ЮТТипыДанныхСлужебный + + + ru + Типы данных + + + + false + true + true + false + true + false + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТТипыДанныхСлужебный/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТТипыДанныхСлужебный/Ext/Module.bsl new file mode 100644 index 0000000..edffc9f --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТТипыДанныхСлужебный/Ext/Module.bsl @@ -0,0 +1,231 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область СлужебныйПрограммныйИнтерфейс + +Функция ПредставлениеТипа(Тип) Экспорт + +#Если ВебКлиент Тогда + ВызватьИсключение ЮТИсключения.МетодНеДоступен("ЮТТипыДанныхСлужебный.ПредставлениеТипа"); +#Иначе + Возврат ИдентификаторТипа(Тип); +#КонецЕсли + +КонецФункции + +Функция ИдентификаторТипа(Тип) Экспорт + +#Если ВебКлиент Тогда + ВызватьИсключение ЮТИсключения.МетодНеДоступен("ЮТТипыДанныхСлужебный.ПредставлениеТипа"); +#Иначе + ЮТПроверкиСлужебный.ПроверитьТипПараметра(Тип, Тип("Тип"), "ЮТТипыДанныхСлужебный.ИдентификаторТипа", "Тип"); + + Если Тип = Тип("Дата") Тогда + ИдентификаторТипа = "date"; + ИначеЕсли Тип = Тип("Число") Тогда + ИдентификаторТипа = "number"; + Иначе + //@skip-check Undefined variable + ИмяТипаСПространствомИмен = СериализаторXDTO.ЗаписатьXDTO(Тип).ЛексическоеЗначение; + ИдентификаторТипа = СтрРазделить(ИмяТипаСПространствомИмен, "}")[1]; + КонецЕсли; + + Возврат ИдентификаторТипа; +#КонецЕсли + +КонецФункции + +Функция ТипПоИдентификатору(ИдентификаторТипа) Экспорт + +#Если ВебКлиент Тогда + ВызватьИсключение ЮТИсключения.МетодНеДоступен("ЮТТипыДанныхСлужебный.ПредставлениеТипа"); +#Иначе + Возврат Тип(ИдентификаторТипа); +#КонецЕсли + +КонецФункции + +Функция ЭтоСсылочныйТип(Тип) Экспорт + + Возврат Тип <> Неопределено И ОписаниеТиповЛюбаяСсылка().СодержитТип(Тип); + +КонецФункции + +Функция ЭтоМенеджерЗаписи(ТипЗначения) Экспорт + + ПредставлениеТипа = ПредставлениеТипа(ТипЗначения); + Возврат СтрНайти(ПредставлениеТипа, "RecordManager.") > 0; + +КонецФункции + +Функция ЭтоТипОбъекта(ТипЗначения) Экспорт + + ПредставлениеТипа = ПредставлениеТипа(ТипЗначения); + Возврат СтрНайти(ПредставлениеТипа, "Object.") > 0; + +КонецФункции + +Функция ЭтоТипНабораЗаписей(ТипЗначения) Экспорт + + ПредставлениеТипа = ПредставлениеТипа(ТипЗначения); + Возврат СтрНайти(ПредставлениеТипа, "RecordSet.") > 0; + +КонецФункции + +Функция ЭтоТипОбъектаОбработкиОтчета(ТипЗначения) Экспорт + + ПредставлениеТипа = ПредставлениеТипа(ТипЗначения); + Возврат СтрНачинаетсяС(ПредставлениеТипа, "DataProcessorObject.") Или СтрНачинаетсяС(ПредставлениеТипа, "ReportObject."); + +КонецФункции + +Функция ЭтоТипМенеджера(ТипЗначения) Экспорт + + ПредставлениеТипа = ПредставлениеТипа(ТипЗначения); + Возврат СтрНайти(ПредставлениеТипа, "Manager.") > 0; + +КонецФункции + +Функция ТипОбъектаСсылки(ТипСсылки) Экспорт + +#Если ВебКлиент Тогда + ВызватьИсключение ЮТИсключения.МетодНеДоступен("ЮТТипыДанныхСлужебный.ТипОбъектаСсылки"); +#Иначе + ТипXML = СериализаторXDTO.XMLТип(ТипСсылки); + ИмяТипа = СтрЗаменить(ТипXML.ИмяТипа, "Ref.", "Object."); + + Возврат СериализаторXDTO.ИзXMLТипа(ИмяТипа, ТипXML.URIПространстваИмен); +#КонецЕсли + +КонецФункции + +Функция ЭтоТипПеречисления(ТипЗначения) Экспорт + + ПредставлениеТипа = ПредставлениеТипа(ТипЗначения); + Возврат СтрНачинаетсяС(ПредставлениеТипа, "EnumRef."); + +КонецФункции + +Функция ОписаниеТиповЛюбаяСсылка() Экспорт + + Возврат ЮТСлужебныйПовторногоИспользования.ОписаниеТиповЛюбаяСсылка(); + +КонецФункции + +#Область СистемныеПеречисления + +Функция ЭтоСистемноеПеречисление(Тип) Экспорт + + Возврат ТипыСистемныхПеречислений().СодержитТип(Тип); + +КонецФункции + +Функция ТипыСистемныхПеречислений() Экспорт + + Возврат Новый ОписаниеТипов( + "ВидДвиженияБухгалтерии, + |ВидДвиженияНакопления, + |ВидПериодаРегистраРасчета, + |ВидСчета, + |ВидТочкиМаршрутаБизнесПроцесса, + |ИспользованиеГруппИЭлементов, + |ИспользованиеСреза, + |ИспользованиеРежимаПроведения, + |РежимАвтоВремя, + |РежимЗаписиДокумента, + |РежимПроведенияДокумента, + |ПериодичностьАгрегатаРегистраНакопления, + |ИспользованиеАгрегатаРегистраНакопления"); + +КонецФункции + +Функция ИмяСистемногоПеречисления(Тип) Экспорт + + Возврат Строка(Тип); + +КонецФункции + +Функция ЭтоКоллекцияПримитивныхТипов(Типы) Экспорт + + Для Каждого Тип Из Типы Цикл + + Если НЕ ЭтоПримитивныйТип(Тип) Тогда + Возврат Ложь; + КонецЕсли; + + КонецЦикла; + + Возврат Истина; + +КонецФункции + +Функция ЭтоПримитивныйТип(Тип) Экспорт + + ПримитивныеТипы = ЮТСлужебныйПовторногоИспользования.ПримитивныеТипы(); + + ТипПараметра = ТипЗнч(Тип); + + Если ТипПараметра = Тип("Тип") Тогда + Возврат ПримитивныеТипы.Найти(Тип) <> Неопределено; + КонецЕсли; + + Для Каждого Тип Из Тип.Типы() Цикл + + Если ПримитивныеТипы.Найти(Тип) = Неопределено Тогда + Возврат Ложь; + КонецЕсли; + + КонецЦикла; + + Возврат Истина; + +КонецФункции + +#КонецОбласти + +Функция ЭтоСтруктура(ТипЗначения) Экспорт + + Возврат ТипЗначения = Тип("Структура") + Или ТипЗначения = Тип("ФиксированнаяСтруктура"); + +КонецФункции + +Функция ЭтоМассива(ТипЗначения) Экспорт + + Возврат ТипЗначения = Тип("Массив") + Или ТипЗначения = Тип("ФиксированныйМассив"); + +КонецФункции + +Функция ЭтоСоответствие(ТипЗначения) Экспорт + + Возврат ТипЗначения = Тип("Соответствие") + Или ТипЗначения = Тип("ФиксированноеСоответствие"); + +КонецФункции + +Функция ЭтоКлючЗначение(ТипЗначения) Экспорт + + Возврат ТипЗначения = Тип("Структура") + Или ТипЗначения = Тип("ФиксированнаяСтруктура") + Или ТипЗначения = Тип("Соответствие") + Или ТипЗначения = Тип("ФиксированноеСоответствие"); + +КонецФункции + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТУтверждения.xml b/src/cfe/YAXUnit/CommonModules/ЮТУтверждения.xml new file mode 100644 index 0000000..6f140b7 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТУтверждения.xml @@ -0,0 +1,23 @@ + + + + + ЮТУтверждения + + + ru + Утверждения + + + + false + true + true + false + true + false + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТУтверждения/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТУтверждения/Ext/Module.bsl new file mode 100644 index 0000000..03d1d7e --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТУтверждения/Ext/Module.bsl @@ -0,0 +1,1945 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область ПрограммныйИнтерфейс + +// Инициализирует модуль для проверки утверждений. +// +// * Запоминает проверяемое значение. +// * Запоминает описание. +// * Сбрасывает настройки предыдущих утверждений. +// +// Утверждения формируются методами этого модуля. +// +// Параметры: +// ПроверяемоеЗначение - Произвольный - Проверяемое фактическое значение +// Сообщение - Строка - Описание проверки, которое будет выведено при возникновении ошибки +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +// Примеры +// ЮТУтверждения.Что(...).ЭтоИстина(...); +// +Функция Что(Знач ПроверяемоеЗначение, Знач Сообщение = "") Экспорт + + Контекст = НовыйКонтекстУтверждения(ПроверяемоеЗначение); + + Контекст.ОбъектПроверки.Значение = ПроверяемоеЗначение; + Контекст.ПрефиксОшибки = Сообщение; + + СброситьКонтекст(); + ЮТКонтекстСлужебный.УстановитьКонтекстУтверждений(Контекст); + + Возврат ЮТУтверждения; + +КонецФункции + +// Запоминает описание метода (имя и параметры) для последующей проверки. +// +// Параметры: +// ИмяМетода - Строка - Наименование метода +// ПараметрыМетода - Массив из Произвольный - Параметры вызываемого метода +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция Метод(Знач ИмяМетода, Знач ПараметрыМетода = Неопределено) Экспорт + + Контекст = Контекст(); + + ПроверитьТипЗначения(Контекст, ИмяМетода, "Строка", "имени метода", Истина); + ПроверитьТипЗначения(Контекст, ПараметрыМетода, "Массив", "параметров метода", Истина); + + Контекст = Контекст(); + Контекст.ИмяМетода = ИмяМетода; + Контекст.ПараметрыМетода = ПараметрыМетода; + + Возврат ЮТУтверждения; + +КонецФункции + +// Добавляет параметр метода для последующего вызова метода и проверки. +// +// Параметры: +// ЗначениеПараметра - Произвольный - Параметр вызываемого метода +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция Параметр(Знач ЗначениеПараметра) Экспорт + + Контекст = Контекст(); + + Если НЕ ЗначениеЗаполнено(Контекст.ИмяМетода) Тогда + ЮТРегистрацияОшибокСлужебный.СгенерироватьОшибкуВыполнения("Перед установкой параметров нужно указать метод", Контекст); + КонецЕсли; + + Если Контекст.ПараметрыМетода = Неопределено Тогда + Контекст.ПараметрыМетода = ЮТКоллекции.ЗначениеВМассиве(ЗначениеПараметра); + Иначе + Контекст.ПараметрыМетода.Добавить(ЗначениеПараметра); + КонецЕсли; + + Возврат ЮТУтверждения; + +КонецФункции + +// Устанавливает описание проверяемого объекта. +// +// Параметры: +// Представление - Строка - Представление +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция ИмеющееПредставление(Представление) Экспорт + + Контекст().ОбъектПроверки.Представление = Представление; + Возврат ЮТУтверждения; + +КонецФункции + +// Проверяет наличие свойства и запоминает его для последующих проверок. +// +// Важно, следующие проверки будут относится к этому свойству. +// Для переключения на проверки объекта можно воспользоваться методом см. Объект. +// +// Параметры: +// ИмяСвойства - Строка - Наименование свойства объекта. +// Возможно обращение к вложенным свойствам через точку +// ОписаниеПроверки - Строка - Описание конкретной проверки +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция Свойство(Знач ИмяСвойства, Знач ОписаниеПроверки = Неопределено) Экспорт + + Контекст = Контекст(); + УстановитьОписаниеПроверки(Контекст, ОписаниеПроверки); + Контекст.ОбъектПроверки.ИмяСвойства = Неопределено; // Очищаем для формирования корректного сообщения об ошибке + + Путь = НормализованныйПутьКСвойству(Контекст.ОбъектПроверки.Значение, ИмяСвойства, Истина); + + Контекст.ОбъектПроверки.ИмяСвойства = ИмяСвойства; + Контекст.НормализованныйПутьКСвойству = Путь; + + Возврат ЮТУтверждения; + +КонецФункции + +// Проверяет отсутствие свойства основного объекта. +// А также сбрасывает ранее установленное проверяемое свойство (см. Свойство). +// +// Параметры: +// ИмяСвойства - Строка - Наименование свойства объекта. +// Возможно обращение к вложенным свойствам через точку +// ОписаниеПроверки - Строка - Описание конкретной проверки +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция НетСвойства(Знач ИмяСвойства, Знач ОписаниеПроверки = Неопределено) Экспорт + + Контекст = Контекст(); + УстановитьОписаниеПроверки(Контекст, ОписаниеПроверки); + Контекст.ОбъектПроверки.ИмяСвойства = Неопределено; // Очищаем для формирования корректного сообщения об ошибке + + Если ЗначениеСодержитСвойство(Контекст.ОбъектПроверки.Значение, ИмяСвойства) Тогда + СгенерироватьОшибкуСравнения(СтрШаблон("не содержит свойство `%1`", ИмяСвойства), Неопределено, ИмяСвойства); + КонецЕсли; + + Возврат ЮТУтверждения; + +КонецФункции + +// Проверяет наличие элемента с указанным индексом и позиционируется на нем для последующих проверок. +// +// Важно, следующие проверки будут относится к этому элементу. +// Для переключения на проверки объекта можно воспользоваться методом см. Объект. +// +// Параметры: +// Индекс - Число - Индекс элемента коллекции +// ОписаниеПроверки - Строка - Описание конкретной проверки +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция Элемент(Знач Индекс, Знач ОписаниеПроверки = Неопределено) Экспорт + + Возврат Свойство(Индекс, ОписаниеПроверки); + +КонецФункции + +// Используется после вызова метода см. Свойство, для переключения с ранее указанного свойства на объект. +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция Объект() Экспорт + + Контекст = Контекст(); + Контекст.ОбъектПроверки.ИмяСвойства = Неопределено; + + Возврат ЮТУтверждения; + +КонецФункции + +#Область УтвержденияПредикатов + +// Проверяет установленное значение Контекста (или его свойство) на равенство ожидаемому. +// +// При сравнении также проверяется совпадение типов проверяемого и ожидаемого значения. +// Для сериализуемых объектов проверяется равенство по значению. +// +// Параметры: +// ОжидаемоеЗначение - Произвольный - Ожидается, что значение Контекста (или его свойство) равно этому значению +// ОписаниеПроверки - Строка - Описание конкретной проверки +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция Равно(Знач ОжидаемоеЗначение, Знач ОписаниеПроверки = Неопределено) Экспорт + + ПараметрыСравнения = Новый Структура("ГлубокийАнализ", Истина); + ПроверитьПредикат(ЮТПредикаты.Выражения().Равно, ОжидаемоеЗначение, ОписаниеПроверки, ПараметрыСравнения); + Возврат ЮТУтверждения; + +КонецФункции + +// Проверяет установленное значение Контекста (или его свойство) на НЕ равенство ожидаемому. +// +// При сравнении также проверяется совпадение типов проверяемого и ожидаемого значения +// Для сериализуемых значений проверяется равенство по значению +// +// Параметры: +// ОжидаемоеЗначение - Произвольный - Ожидается, что значение Контекста (или его свойство) НЕ равно этому значению +// ОписаниеПроверки - Строка - Описание конкретной проверки +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция НеРавно(Знач ОжидаемоеЗначение, Знач ОписаниеПроверки = Неопределено) Экспорт + + ПараметрыСравнения = Новый Структура("ГлубокийАнализ", Истина); + ПроверитьПредикат(ЮТПредикаты.Выражения().НеРавно, ОжидаемоеЗначение, ОписаниеПроверки, ПараметрыСравнения); + Возврат ЮТУтверждения; + +КонецФункции + +// Проверяет установленное значение Контекста (или его свойство), оно должно быть больше ожидаемого. +// +// Параметры: +// ОжидаемоеЗначение - Произвольный - Ожидается, что значение Контекста (или его свойство) Больше этого значения +// ОписаниеПроверки - Строка - Описание конкретной проверки +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция Больше(Знач ОжидаемоеЗначение, Знач ОписаниеПроверки = Неопределено) Экспорт + + ПроверитьПредикат(ЮТПредикаты.Выражения().Больше, ОжидаемоеЗначение, ОписаниеПроверки); + Возврат ЮТУтверждения; + +КонецФункции + +// Проверяет установленное значение Контекста (или его свойство), оно должно быть больше или равно ожидаемому. +// +// Параметры: +// ОжидаемоеЗначение - Произвольный - Ожидается, что значение Контекста (или его свойство) Больше этого значения или равно ему +// ОписаниеПроверки - Строка - Описание конкретной проверки +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция БольшеИлиРавно(Знач ОжидаемоеЗначение, Знач ОписаниеПроверки = Неопределено) Экспорт + + ПроверитьПредикат(ЮТПредикаты.Выражения().БольшеРавно, ОжидаемоеЗначение, ОписаниеПроверки); + Возврат ЮТУтверждения; + +КонецФункции + +// Проверяет установленное значение Контекста (или его свойство), оно должно быть меньше ожидаемого. +// +// Параметры: +// ОжидаемоеЗначение - Произвольный - Ожидается, что значение Контекста (или его свойство) меньше этого значения +// ОписаниеПроверки - Строка - Описание конкретной проверки +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция Меньше(Знач ОжидаемоеЗначение, Знач ОписаниеПроверки = Неопределено) Экспорт + + ПроверитьПредикат(ЮТПредикаты.Выражения().Меньше, ОжидаемоеЗначение, ОписаниеПроверки); + Возврат ЮТУтверждения; + +КонецФункции + +// Проверяет установленное значение Контекста (или его свойство), оно должно быть меньше или равно ожидаемому. +// +// Параметры: +// ОжидаемоеЗначение - Произвольный - Ожидается, что значение Контекста (или его свойство) меньше этого значения или равно ему +// ОписаниеПроверки - Строка - Описание конкретной проверки +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция МеньшеИлиРавно(Знач ОжидаемоеЗначение, Знач ОписаниеПроверки = Неопределено) Экспорт + + ПроверитьПредикат(ЮТПредикаты.Выражения().МеньшеРавно, ОжидаемоеЗначение, ОписаниеПроверки); + Возврат ЮТУтверждения; + +КонецФункции + +// Проверяет установленное значение Контекста (или его свойство) на "заполненность" (обертка для `ЗначениеЗаполнено`). +// +// Параметры: +// ОписаниеПроверки - Строка - Описание конкретной проверки +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция Заполнено(Знач ОписаниеПроверки = Неопределено) Экспорт + + ПроверитьПредикат(ЮТПредикаты.Выражения().Заполнено, , ОписаниеПроверки); + Возврат ЮТУтверждения; + +КонецФункции + +// Проверяет установленное значение Контекста (или его свойство) на "не заполненность" (обертка для `ЗначениеЗаполнено`) +// +// Параметры: +// ОписаниеПроверки - Строка - Описание конкретной проверки +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция НеЗаполнено(Знач ОписаниеПроверки = Неопределено) Экспорт + + ПроверитьПредикат(ЮТПредикаты.Выражения().НеЗаполнено, , ОписаниеПроверки); + Возврат ЮТУтверждения; + +КонецФункции + +// Проверяет установленное значение Контекста (или его свойство) на соответствие переданному типу. +// +// Параметры: +// ОжидаемоеЗначение - Строка, Тип, ОписаниеТипов - Ожидается, что значение Контекста (или его свойство) имеет данный тип +// ОписаниеПроверки - Строка - Описание конкретной проверки +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция ИмеетТип(Знач ОжидаемоеЗначение, Знач ОписаниеПроверки = Неопределено) Экспорт + + ПроверитьПредикат(ЮТПредикаты.Выражения().ИмеетТип, ОжидаемоеЗначение, ОписаниеПроверки); + Возврат ЮТУтверждения; + +КонецФункции + +// Проверяет установленное значение Контекста (или его свойство) на несоответствие переданному типу. +// +// Параметры: +// ОжидаемоеЗначение - Строка, Тип, ОписаниеТипов - Ожидается, что значение Контекста (или его свойство) НЕ имеет данный тип +// ОписаниеПроверки - Строка - Описание конкретной проверки +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция НеИмеетТип(Знач ОжидаемоеЗначение, Знач ОписаниеПроверки = Неопределено) Экспорт + + ПроверитьПредикат(ЮТПредикаты.Выражения().НеИмеетТип, ОжидаемоеЗначение, ОписаниеПроверки); + Возврат ЮТУтверждения; + +КонецФункции + +// Проверяет установленное значение Контекста (или его свойство) на наличие в нем искомого. +// +// Проверка поддерживается для следующих типов проверяемого значения: +// +// - Строка - по вхождению +// - Массив - по наличию равного элемента +// - Структура - по наличию равного значения +// - Соответствие - по наличию равного значения +// - СписокЗначений - по наличию равного значения +// - ФиксированныйМассив - по наличию равного значения +// - ФиксированнаяСтруктура - по наличию равного значения +// - ФиксированноеСоответствие - по наличию равного значения +// - Произвольный итерируемый объект для проверки на соответствие предикату +// +// При сравнении также проверяется совпадение типов +// +// Параметры: +// ОжидаемоеЗначение - Произвольный - Ожидается, что значение Контекста (или его свойство) содержит указанное значение +// - ОбщийМодуль - Модуль настройки предикатов, см. ЮТест.Предикат +// ОписаниеПроверки - Строка - Описание конкретной проверки +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция Содержит(Знач ОжидаемоеЗначение, Знач ОписаниеПроверки = Неопределено) Экспорт + + Если ЮТПредикатыСлужебныйКлиентСервер.ЭтоПредикат(ОжидаемоеЗначение) Тогда + ПроверитьСодержаниеПредиката(ОжидаемоеЗначение, ОписаниеПроверки, Ложь); + Иначе + ПроверитьПредикат(ЮТПредикаты.Выражения().Содержит, ОжидаемоеЗначение, ОписаниеПроверки); + КонецЕсли; + + Возврат ЮТУтверждения; + +КонецФункции + +// Проверяет установленное значение Контекста (или его свойство) на наличие в нем искомого. +// +// Проверка поддерживается для следующих типов проверяемого значения: +// +// - Строка - по отсутствию вхождению +// - Массив - по отсутствию равного элемента +// - Структура - по отсутствию равного значения +// - Соответствие - по отсутствию равного значения +// - СписокЗначений - по отсутствию равного значения +// - ФиксированныйМассив - по отсутствию равного значения +// - ФиксированнаяСтруктура - по отсутствию равного значения +// - ФиксированноеСоответствие - по отсутствию равного значения +// - Произвольный итерируемый объект для проверки на соответствие предикату +// +// При сравнении также проверяется совпадение типов +// +// Параметры: +// ОжидаемоеЗначение - Произвольный - Ожидается, что значение Контекста (или его свойство) НЕ содержит указанное +// - ОбщийМодуль - Модуль настройки предикатов, см. ЮТест.Предикат +// ОписаниеПроверки - Строка - Описание конкретной проверки +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция НеСодержит(Знач ОжидаемоеЗначение, Знач ОписаниеПроверки = Неопределено) Экспорт + + Если ЮТПредикатыСлужебныйКлиентСервер.ЭтоПредикат(ОжидаемоеЗначение) Тогда + ПроверитьСодержаниеПредиката(ОжидаемоеЗначение, ОписаниеПроверки, Истина); + Иначе + ПроверитьПредикат(ЮТПредикаты.Выражения().НеСодержит, ОжидаемоеЗначение, ОписаниеПроверки); + КонецЕсли; + + Возврат ЮТУтверждения; + +КонецФункции + +// Проверяет установленное значение Контекста (или его свойство) на наличие подстроки, соответствующей регулярному выражению +// +// Параметры: +// Шаблон - Строка - Регулярное выражение, по которому ищем подстроку +// ОписаниеПроверки - Строка - Описание конкретной проверки +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция СодержитСтрокуПоШаблону(Знач Шаблон, Знач ОписаниеПроверки = Неопределено) Экспорт + + ПроверитьПредикат(ЮТПредикаты.Выражения().СодержитСтрокуПоШаблону, Шаблон, ОписаниеПроверки); + Возврат ЮТУтверждения; + +КонецФункции + +// Проверяет установленное значение Контекста (или его свойство) на отсутствие подстроки, соответствующей регулярному выражению +// +// Параметры: +// Шаблон - Строка - Регулярное выражение, по которому ищем подстроку +// ОписаниеПроверки - Строка - Описание конкретной проверки +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция НеСодержитСтрокуПоШаблону(Знач Шаблон, Знач ОписаниеПроверки = Неопределено) Экспорт + + ПроверитьПредикат(ЮТПредикаты.Выражения().НеСодержитСтрокуПоШаблону, Шаблон, ОписаниеПроверки); + Возврат ЮТУтверждения; + +КонецФункции + +// Проверяет наличие свойства у объекта/его свойства. +// В отличии от метода см. Свойство не позиционируется на указанное свойство. +// Параметры: +// ИмяСвойства - Строка - Наименование свойства объекта. +// Возможно обращение к вложенным свойствам через точку +// ОписаниеПроверки - Строка - Описание конкретной проверки +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция ИмеетСвойство(Знач ИмяСвойства, Знач ОписаниеПроверки = Неопределено) Экспорт + + ПроверитьПредикат(ЮТПредикаты.Выражения().ИмеетСвойство, ИмяСвойства, ОписаниеПроверки); + Возврат ЮТУтверждения; + +КонецФункции + +// Проверяет отсутствие свойства у объекта/его свойства. +// В отличии от метода см. НетСвойства не сбрасывает позиционирование проверки. +// +// Параметры: +// ИмяСвойства - Строка - Наименование свойства объекта. +// Возможно обращение к вложенным свойствам через точку +// ОписаниеПроверки - Строка - Описание конкретной проверки +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция НеИмеетСвойства(Знач ИмяСвойства, Знач ОписаниеПроверки = Неопределено) Экспорт + + ПроверитьПредикат(ЮТПредикаты.Выражения().НеИмеетСвойство, ИмяСвойства, ОписаниеПроверки); + Возврат ЮТУтверждения; + +КонецФункции + +// Проверяет значение (или его свойство), оно должно входить в указанный список. +// +// Параметры: +// Значения - Массив из Произвольный - Значения для проверки +// - СписокЗначений из Произвольный - Значения для проверки +// ОписаниеПроверки - Строка - Описание конкретной проверки +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция ВСписке(Значения, ОписаниеПроверки = Неопределено) Экспорт + + ПроверитьПредикат(ЮТПредикаты.Выражения().ВСписке, Значения, ОписаниеПроверки); + Возврат ЮТУтверждения; + +КонецФункции + +#КонецОбласти + +// Проверяет наличие свойств и их значения у проверяемого объекта (или его свойства). +// +// Параметры: +// ОжидаемоеЗначение - Структура - Проверяемый объект должен иметь свойства указанные в параметре +// ОписаниеПроверки - Строка - Описание конкретной проверки +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция ИмеетСвойстваРавные(Знач ОжидаемоеЗначение, Знач ОписаниеПроверки = Неопределено) Экспорт + + Контекст = Контекст(); + УстановитьОписаниеПроверки(Контекст, ОписаниеПроверки); + ПроверяемоеЗначение = ПроверяемоеЗначение(Контекст); + ОбъектыРавны(ПроверяемоеЗначение, ОжидаемоеЗначение); + + Возврат ЮТУтверждения; + +КонецФункции + +// Проверяет установленное значение Контекста (или его свойство) на равенство `Истина)`. +// При сравнении также проверяется совпадение типов проверяемого и ожидаемого значения. +// +// Параметры: +// ОписаниеПроверки - Строка - Описание конкретной проверки +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция ЭтоИстина(Знач ОписаниеПроверки = Неопределено) Экспорт + + Контекст = Контекст(); + УстановитьОписаниеПроверки(Контекст, ОписаниеПроверки); + СравнитьЗначения(Контекст, Истина, Ложь, "является истиной"); + Возврат ЮТУтверждения; + +КонецФункции + +// Проверяет установленное значение Контекста (или его свойство)на НЕ равенство `Истина`. +// При сравнении также проверяется совпадение типов проверяемого и ожидаемого значения. +// +// Параметры: +// ОписаниеПроверки - Строка - Описание конкретной проверки +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция ЭтоНеИстина(Знач ОписаниеПроверки = Неопределено) Экспорт + + Контекст = Контекст(); + УстановитьОписаниеПроверки(Контекст, ОписаниеПроверки); + СравнитьЗначения(Контекст, Истина, Истина, "является истиной"); + Возврат ЮТУтверждения; + +КонецФункции + +// Проверяет установленное значение Контекста (или его свойство) на равенство `Ложь`. +// При сравнении также проверяется совпадение типов проверяемого и ожидаемого значения. +// +// Параметры: +// ОписаниеПроверки - Строка - Описание конкретной проверки +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция ЭтоЛожь(Знач ОписаниеПроверки = Неопределено) Экспорт + + Контекст = Контекст(); + УстановитьОписаниеПроверки(Контекст, ОписаниеПроверки); + СравнитьЗначения(Контекст, Ложь, Ложь, "является ложью"); + Возврат ЮТУтверждения; + +КонецФункции + +// Проверяет установленное значение Контекста (или его свойство) на НЕ равенство `Ложь`. +// При сравнении также проверяется совпадение типов проверяемого и ожидаемого значения. +// +// Параметры: +// ОписаниеПроверки - Строка - Описание конкретной проверки +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция ЭтоНеЛожь(Знач ОписаниеПроверки = Неопределено) Экспорт + + Контекст = Контекст(); + УстановитьОписаниеПроверки(Контекст, ОписаниеПроверки); + СравнитьЗначения(Контекст, Ложь, Истина, "является ложью"); + Возврат ЮТУтверждения; + +КонецФункции + +// Проверяет установленное значение Контекста (или его свойство) на "существование", т.е. отличие от `Null` и `Неопределено`. +// +// Параметры: +// ОписаниеПроверки - Строка - Описание конкретной проверки +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция Существует(Знач ОписаниеПроверки = Неопределено) Экспорт + + Контекст = Контекст(); + УстановитьОписаниеПроверки(Контекст, ОписаниеПроверки); + ПроверитьСуществование(Контекст, Ложь); + Возврат ЮТУтверждения; + +КонецФункции + +// Проверяет установленное значение Контекста (или его свойство) на "не существование", т.е. оно равно `Null` или `Неопределено`. +// +// Параметры: +// ОписаниеПроверки - Строка - Описание конкретной проверки +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция НеСуществует(Знач ОписаниеПроверки = Неопределено) Экспорт + + Контекст = Контекст(); + УстановитьОписаниеПроверки(Контекст, ОписаниеПроверки); + ПроверитьСуществование(Контекст, Истина); + Возврат ЮТУтверждения; + +КонецФункции + +// Проверяет установленное значение Контекста (или его свойство) не равенство `Неопределено`. +// +// Параметры: +// ОписаниеПроверки - Строка - Описание конкретной проверки +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция ЭтоНеопределено(Знач ОписаниеПроверки = Неопределено) Экспорт + + Контекст = Контекст(); + УстановитьОписаниеПроверки(Контекст, ОписаниеПроверки); + СравнитьЗначения(Контекст, Неопределено, Ложь, "является неопределено"); + Возврат ЮТУтверждения; + +КонецФункции + +// Проверяет установленное значение Контекста (или его свойство) на не равенство `Неопределено`. +// +// Параметры: +// ОписаниеПроверки - Строка - Описание конкретной проверки +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция ЭтоНеНеопределено(Знач ОписаниеПроверки = Неопределено) Экспорт + + Контекст = Контекст(); + УстановитьОписаниеПроверки(Контекст, ОписаниеПроверки); + СравнитьЗначения(Контекст, Неопределено, Истина, "является неопределено"); + Возврат ЮТУтверждения; + +КонецФункции + +// Проверяет установленное значение Контекста (или его свойство) на равенство `Null`. +// +// Параметры: +// ОписаниеПроверки - Строка - Описание конкретной проверки +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция ЭтоNull(Знач ОписаниеПроверки = Неопределено) Экспорт + + Контекст = Контекст(); + УстановитьОписаниеПроверки(Контекст, ОписаниеПроверки); + СравнитьЗначения(Контекст, Null, Ложь, "является null"); + Возврат ЮТУтверждения; + +КонецФункции + +// Проверяет установленное значение Контекста (или его свойство) на не равенство `Null`. +// +// Параметры: +// ОписаниеПроверки - Строка - Описание конкретной проверки +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция ЭтоНеNull(Знач ОписаниеПроверки = Неопределено) Экспорт + + Контекст = Контекст(); + УстановитьОписаниеПроверки(Контекст, ОписаниеПроверки); + СравнитьЗначения(Контекст, Null, Истина, "является null"); + Возврат ЮТУтверждения; + +КонецФункции + +// Проверяет установленное значение Контекста (или его свойство) на длину или размер коллекции. +// +// Проверка поддерживается для следующих типов проверяемого значения: +// - Строка +// - Массив +// - Структура +// - Соответствие +// - СписокЗначений +// - ФиксированныйМассив +// - ФиксированнаяСтруктура +// - ФиксированноеСоответствие +// - ТаблицаЗначения +// +// Параметры: +// ОжидаемоеЗначение - Число - Ожидается, что значение Контекста (или его свойство) имеет указанную длину или размер +// ОписаниеПроверки - Строка - Описание конкретной проверки +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция ИмеетДлину(Знач ОжидаемоеЗначение, Знач ОписаниеПроверки = Неопределено) Экспорт + + Контекст = Контекст(); + УстановитьОписаниеПроверки(Контекст, ОписаниеПроверки); + ПроверитьТипЗначения(Контекст, ОжидаемоеЗначение, "Число"); + + ФактическаяДлина = ДлинаПроверяемогоЗначения(Контекст); + Результат = ФактическаяДлина = ОжидаемоеЗначение; + + Сообщение = СтрШаблон("длиной (размером) `%1` имеет длину (размер) `%2`", ФактическаяДлина, ОжидаемоеЗначение); + ОбработатьРезультатСравнения(Результат, Сообщение, Ложь, ФактическаяДлина, ОжидаемоеЗначение); + Возврат ЮТУтверждения; + +КонецФункции + +// Проверяет установленное значение Контекста (или его свойство) на длину или размер коллекции. +// +// Проверка поддерживается для следующих типов проверяемого значения: +// - Строка +// - Массив +// - Структура +// - Соответствие +// - СписокЗначений +// - ФиксированныйМассив +// - ФиксированнаяСтруктура +// - ФиксированноеСоответствие +// - ТаблицаЗначения +// +// Параметры: +// ОжидаемоеЗначение - Число - Ожидается, что значение Контекста (или его свойство) имеет указанную длину или размер +// ОписаниеПроверки - Строка - Описание конкретной проверки +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция ИмеетДлинуБольше(Знач ОжидаемоеЗначение, Знач ОписаниеПроверки = Неопределено) Экспорт + + Контекст = Контекст(); + УстановитьОписаниеПроверки(Контекст, ОписаниеПроверки); + ПроверитьТипЗначения(Контекст, ОжидаемоеЗначение, "Число"); + + ФактическаяДлина = ДлинаПроверяемогоЗначения(Контекст); + Результат = ФактическаяДлина > ОжидаемоеЗначение; + + Сообщение = СтрШаблон("длиной (размером) `%1` имеет длину (размер) больше `%2`", ФактическаяДлина, ОжидаемоеЗначение); + ОбработатьРезультатСравнения(Результат, Сообщение, Ложь, ФактическаяДлина, ОжидаемоеЗначение); + Возврат ЮТУтверждения; + +КонецФункции + +// Проверяет установленное значение Контекста (или его свойство) на длину или размер коллекции. +// +// Проверка поддерживается для следующих типов проверяемого значения: +// - Строка +// - Массив +// - Структура +// - Соответствие +// - СписокЗначений +// - ФиксированныйМассив +// - ФиксированнаяСтруктура +// - ФиксированноеСоответствие +// - ТаблицаЗначения +// +// Параметры: +// ОжидаемоеЗначение - Число - Ожидается, что значение Контекста (или его свойство) имеет указанную длину или размер +// ОписаниеПроверки - Строка - Описание конкретной проверки +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция ИмеетДлинуМеньше(Знач ОжидаемоеЗначение, Знач ОписаниеПроверки = Неопределено) Экспорт + + Контекст = Контекст(); + УстановитьОписаниеПроверки(Контекст, ОписаниеПроверки); + ПроверитьТипЗначения(Контекст, ОжидаемоеЗначение, "Число"); + + ФактическаяДлина = ДлинаПроверяемогоЗначения(Контекст); + Результат = ФактическаяДлина < ОжидаемоеЗначение; + + Сообщение = СтрШаблон("длиной (размером) `%1` имеет длину (размер) меньше `%2`", ФактическаяДлина, ОжидаемоеЗначение); + ОбработатьРезультатСравнения(Результат, Сообщение, Ложь, ФактическаяДлина, ОжидаемоеЗначение); + Возврат ЮТУтверждения; + +КонецФункции + +// Проверяет установленное значение Контекста (или его свойство) на длину или размер коллекции, которые не должны совпадать с указанным значением. +// +// Проверка поддерживается для следующих типов проверяемого значения: +// - Строка +// - Массив +// - Структура +// - Соответствие +// - СписокЗначений +// - ФиксированныйМассив +// - ФиксированнаяСтруктура +// - ФиксированноеСоответствие +// - ТаблицаЗначения +// +// Параметры: +// ОжидаемоеЗначение - Число - Ожидается, что значение Контекста (или его свойство) не имеет указанную дину или размер +// ОписаниеПроверки - Строка - Описание конкретной проверки +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция НеИмеетДлину(Знач ОжидаемоеЗначение, Знач ОписаниеПроверки = Неопределено) Экспорт + + Контекст = Контекст(); + УстановитьОписаниеПроверки(Контекст, ОписаниеПроверки); + ПроверитьТипЗначения(Контекст, ОжидаемоеЗначение, "Число"); + + ФактическаяДлина = ДлинаПроверяемогоЗначения(Контекст); + Результат = ФактическаяДлина <> ОжидаемоеЗначение; + + Сообщение = СтрШаблон("длиной (размером) `%1` не имеет длину (размер) `%2`", ФактическаяДлина, ОжидаемоеЗначение); + ОбработатьРезультатСравнения(Результат, Сообщение, Ложь, ФактическаяДлина, ОжидаемоеЗначение); + Возврат ЮТУтверждения; + +КонецФункции + +#Область ПроверкаМетодов + +// Вызывает метод (см. Метод) объекта контекста и проверяет, выбрасывает ли он исключение. +// Проверяет, что метод упадет по исключению, а текст исключения содержит(включает) указанный. +// +// Параметры: +// ОжидаемоеЗначение - Строка - Ожидается, что сообщение об ошибке будет содержать(включать) данный текст +// ОписаниеПроверки - Строка - Описание конкретной проверки +// ВТранзакции - Булево - Вызов метода выполняется в трананзакции +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция ВыбрасываетИсключение(Знач ОжидаемоеЗначение, Знач ОписаниеПроверки = Неопределено, ВТранзакции = Ложь) Экспорт + + Контекст = Контекст(); + УстановитьОписаниеПроверки(Контекст, ОписаниеПроверки); + Попытка + Модуль = ПроверяемоеЗначение(Контекст); + Результат = ВызватьМетод(Модуль, Контекст.ИмяМетода, Контекст.ПараметрыМетода, ВТранзакции); + Исключение + ЮТРегистрацияОшибокСлужебный.СгенерироватьОшибкуВыполнения(ИнформацияОбОшибке(), Контекст); + КонецПопытки; + + Если НЕ Результат.ИсключениеВозникло Тогда + ТекстОшибки = СтрШаблон("ожидали, что метод `%1` вызовет исключение `%2`, но это не так.", Контекст.ИмяМетода, ОжидаемоеЗначение); + ЮТРегистрацияОшибокСлужебный.УстановитьДанныеОшибкиСравнения(Результат.ТекстИсключения, ОжидаемоеЗначение); + ЮТРегистрацияОшибокСлужебный.ВызватьОшибкуПроверки(ТекстОшибки, Контекст); + ИначеЕсли СтрНайти(Результат.ТекстИсключения, ОжидаемоеЗначение) = 0 Тогда + ТекстОшибки = СтрШаблон("ожидали, что метод `%1` вызовет исключение `%2`, но получили `%3`.", + Контекст.ИмяМетода, + ОжидаемоеЗначение, + Результат.ТекстИсключения); + ЮТРегистрацияОшибокСлужебный.УстановитьДанныеОшибкиСравнения(Результат.ТекстИсключения, ОжидаемоеЗначение); + ЮТРегистрацияОшибокСлужебный.ВызватьОшибкуПроверки(ТекстОшибки, Контекст); + КонецЕсли; + + Возврат ЮТУтверждения; + +КонецФункции + +// Вызывает метод (см. Метод) объекта контекста и проверяет, выбрасывает ли он исключение. +// Проверяет, что метод не упадет по исключению +// или упадет по исключению текст, которого не содержит указанный. +// +// Параметры: +// ОжидаемоеЗначение - Строка - Ожидается, что метод выбросит исключение, текст которого НЕ будет содержать (включать) данный текст +// - Неопределено - Ожидается, что метод отработает без выбора исключения +// ОписаниеПроверки - Строка - Описание конкретной проверки +// ВТранзакции - Булево - Вызов метода выполняется в трананзакции +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция НеВыбрасываетИсключение(Знач ОжидаемоеЗначение = Неопределено, Знач ОписаниеПроверки = Неопределено, ВТранзакции = Ложь) Экспорт + + Контекст = Контекст(); + УстановитьОписаниеПроверки(Контекст, ОписаниеПроверки); + Попытка + Модуль = ПроверяемоеЗначение(Контекст); + Результат = ВызватьМетод(Модуль, Контекст.ИмяМетода, Контекст.ПараметрыМетода, ВТранзакции); + Исключение + ЮТРегистрацияОшибокСлужебный.СгенерироватьОшибкуВыполнения(ИнформацияОбОшибке(), Контекст); + КонецПопытки; + + Если Результат.ИсключениеВозникло Тогда + ЮТРегистрацияОшибокСлужебный.УстановитьДанныеОшибкиСравнения(Результат.ТекстИсключения, ОжидаемоеЗначение); + + Если НЕ ЗначениеЗаполнено(ОжидаемоеЗначение) Тогда + ТекстОшибки = СтрШаблон("ожидали, что метод `%1` не вызовет исключение, но это не так.", Контекст.ИмяМетода); + ЮТРегистрацияОшибокСлужебный.ВызватьОшибкуПроверки(ТекстОшибки, Контекст); + ИначеЕсли СтрНайти(Результат.ТекстИсключения, ОжидаемоеЗначение) <> 0 Тогда + ТекстОшибки = СтрШаблон("ожидали, что метод `%1` не вызовет исключение `%2`, но это не так.", Контекст.ИмяМетода, ОжидаемоеЗначение); + ЮТРегистрацияОшибокСлужебный.ВызватьОшибкуПроверки(ТекстОшибки, Контекст); + КонецЕсли; + КонецЕсли; + + Возврат ЮТУтверждения; + +КонецФункции + +// Проверяет, что установленное значение Контекста (или его свойство) имеет указанный экспортный метод. +// +// +// Параметры: +// ИмяМетода - Строка - Имя метода, наличие которого нужно проверить +// ОписаниеПроверки - Строка - Описание конкретной проверки +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция ИмеетМетод(ИмяМетода, ОписаниеПроверки = Неопределено) Экспорт + + Контекст = Контекст(); + УстановитьОписаниеПроверки(Контекст, ОписаниеПроверки); + + Модуль = ПроверяемоеЗначение(Контекст); + Результат = ЮТМетодыСлужебный.МетодОбъектаСуществует(Модуль, ИмяМетода); + Если НЕ Результат Тогда + Сообщение = СтрШаблон("имеет метод `%1`", ИмяМетода); + СгенерироватьОшибкуСравнения(Сообщение, Модуль, ИмяМетода); + КонецЕсли; + + Возврат ЮТУтверждения; + +КонецФункции + +#КонецОбласти +// Проверяет установленное значение Контекста (или его свойство), ожидается что оно начинается на указанное значение. +// +// При этом проверяемое значение должно быть строкой. +// +// Параметры: +// СтрокаПоиска - Строка - Строка поиска +// ОписаниеПроверки - Строка - Описание конкретной проверки +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция НачинаетсяС(СтрокаПоиска, ОписаниеПроверки = Неопределено) Экспорт + + Контекст = Контекст(); + УстановитьОписаниеПроверки(Контекст, ОписаниеПроверки); + ПроверяемоеЗначение = ПроверяемоеЗначение(Контекст); + ПроверитьТипЗначения(Контекст, ПроверяемоеЗначение, "Строка, ФорматированнаяСтрока", "проверяемого значения"); + ПроверитьТипЗначения(Контекст, СтрокаПоиска, "Строка", "ожидаемого значения"); + ПроверитьЗаполненностьЗначения(Контекст, СтрокаПоиска, "ожидаемое значение"); + + Результат = СтрНачинаетсяС(ПроверяемоеЗначение, СтрокаПоиска); + + Если НЕ Результат Тогда + Сообщение = СтрШаблон("начинается с `%1`", СтрокаПоиска); + СгенерироватьОшибкуСравнения(Сообщение, ПроверяемоеЗначение, СтрокаПоиска); + КонецЕсли; + + Возврат ЮТУтверждения; + +КонецФункции + +// Проверяет установленное значение Контекста (или его свойство), ожидается что оно заканчивается на указанное значение. +// +// При этом проверяемое значение должно быть строкой. +// +// Параметры: +// СтрокаПоиска - Строка - Строка поиска +// ОписаниеПроверки - Строка - Описание конкретной проверки +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция ЗаканчиваетсяНа(СтрокаПоиска, ОписаниеПроверки = Неопределено) Экспорт + + Контекст = Контекст(); + УстановитьОписаниеПроверки(Контекст, ОписаниеПроверки); + ПроверяемоеЗначение = ПроверяемоеЗначение(Контекст); + ПроверитьТипЗначения(Контекст, ПроверяемоеЗначение, "Строка, ФорматированнаяСтрока", "проверяемого значения"); + ПроверитьТипЗначения(Контекст, СтрокаПоиска, "Строка", "ожидаемого значения"); + ПроверитьЗаполненностьЗначения(Контекст, СтрокаПоиска, "ожидаемое значение"); + + Результат = СтрЗаканчиваетсяНа(ПроверяемоеЗначение, СтрокаПоиска); + + Если НЕ Результат Тогда + Сообщение = СтрШаблон("заканчивается на `%1`", СтрокаПоиска); + СгенерироватьОшибкуСравнения(Сообщение, ПроверяемоеЗначение, СтрокаПоиска); + КонецЕсли; + + Возврат ЮТУтверждения; + +КонецФункции + +// Проверяет вхождение установленного значение (или его свойства) в заданный интервал. +// +// Проверяемое значение может находится на границе интервала. +// +// Параметры: +// НачалоИнтервала - Произвольный - Левая граница интервала. Может иметь любой тип, позволяющий сравнивать значения +// ОкончаниеИнтервала - Произвольный - Правая граница. Может иметь любой тип, позволяющий сравнивать значения +// ОписаниеПроверки - Строка - Описание конкретной проверки +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция МеждуВключаяГраницы(НачалоИнтервала, ОкончаниеИнтервала, ОписаниеПроверки = Неопределено) Экспорт + + Контекст = Контекст(); + УстановитьОписаниеПроверки(Контекст, ОписаниеПроверки); + ПроверитьМежду(Контекст, НачалоИнтервала, ОкончаниеИнтервала, Истина, Истина); + Возврат ЮТУтверждения; + +КонецФункции + +// Проверяет вхождение установленного значение (или его свойства) в заданный интервал. +// +// Проверяемое значение не может находится на границе интервала. +// +// Параметры: +// НачалоИнтервала - Произвольный - Левая граница интервала. Может иметь любой тип, позволяющий сравнивать значения +// ОкончаниеИнтервала - Произвольный - Правая граница. Может иметь любой тип, позволяющий сравнивать значения +// ОписаниеПроверки - Строка - Описание конкретной проверки +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция МеждуИсключаяГраницы(НачалоИнтервала, ОкончаниеИнтервала, ОписаниеПроверки = Неопределено) Экспорт + + Контекст = Контекст(); + УстановитьОписаниеПроверки(Контекст, ОписаниеПроверки); + ПроверитьМежду(Контекст, НачалоИнтервала, ОкончаниеИнтервала, Ложь, Ложь); + Возврат ЮТУтверждения; + +КонецФункции + +// Проверяет вхождение установленного значение (или его свойства) в заданный интервал. +// +// Проверяемое значение может находится на начальной границе интервала. +// +// Параметры: +// НачалоИнтервала - Произвольный - Левая граница интервала. Может иметь любой тип, позволяющий сравнивать значения +// ОкончаниеИнтервала - Произвольный - Правая граница. Может иметь любой тип, позволяющий сравнивать значения +// ОписаниеПроверки - Строка - Описание конкретной проверки +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция МеждуВключаяНачалоГраницы(НачалоИнтервала, ОкончаниеИнтервала, ОписаниеПроверки = Неопределено) Экспорт + + Контекст = Контекст(); + УстановитьОписаниеПроверки(Контекст, ОписаниеПроверки); + ПроверитьМежду(Контекст, НачалоИнтервала, ОкончаниеИнтервала, Истина, Ложь); + Возврат ЮТУтверждения; + +КонецФункции + +// Проверяет вхождение установленного значение (или его свойства) в заданный интервал. +// +// Проверяемое значение может находится на конечной границе интервала. +// +// Параметры: +// НачалоИнтервала - Произвольный - Левая граница интервала. Может иметь любой тип, позволяющий сравнивать значения +// ОкончаниеИнтервала - Произвольный - Правая граница. Может иметь любой тип, позволяющий сравнивать значения +// ОписаниеПроверки - Строка - Описание конкретной проверки +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция МеждуВключаяОкончаниеГраницы(НачалоИнтервала, ОкончаниеИнтервала, ОписаниеПроверки = Неопределено) Экспорт + + Контекст = Контекст(); + УстановитьОписаниеПроверки(Контекст, ОписаниеПроверки); + ПроверитьМежду(Контекст, НачалоИнтервала, ОкончаниеИнтервала, Ложь, Истина); + Возврат ЮТУтверждения; + +КонецФункции + +// Проверяет каждый элемент установленного значения (или его свойства), все элементы должны иметь указанное свойство. +// +// Параметры: +// ИмяСвойства - Строка +// ОписаниеПроверки - Строка - Описание конкретной проверки +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция КаждыйЭлементСодержитСвойство(ИмяСвойства, ОписаниеПроверки = Неопределено) Экспорт + + Контекст = Контекст(); + УстановитьОписаниеПроверки(Контекст, ОписаниеПроверки); + ПроверяемоеЗначение = ПроверяемоеЗначение(Контекст); + ОбъектПроверки = "каждый элемент проверяемого значения"; + + Для Каждого Элемент Из ПроверяемоеЗначение Цикл + + Если НЕ ЗначениеСодержитСвойство(Элемент, ИмяСвойства) Тогда + Сообщение = СтрШаблон("содержит свойство `%1`", ИмяСвойства); + СгенерироватьОшибкуСравнения(Сообщение, ПроверяемоеЗначение, ИмяСвойства, ОбъектПроверки); + КонецЕсли; + + КонецЦикла; + + Возврат ЮТУтверждения; + +КонецФункции + +// Проверяет каждый элемент установленного значения (или его свойства), +// все элементы должны иметь указанное свойство, которое равно ожидаемому значению. +// +// Параметры: +// ИмяСвойства - Строка +// ОжидаемоеЗначение - Произвольный - Ожидаемое значение свойства +// ОписаниеПроверки - Строка - Описание конкретной проверки +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция КаждыйЭлементСодержитСвойствоСоЗначением(ИмяСвойства, ОжидаемоеЗначение, ОписаниеПроверки = Неопределено) Экспорт + + Контекст = Контекст(); + УстановитьОписаниеПроверки(Контекст, ОписаниеПроверки); + ПроверяемоеЗначение = ПроверяемоеЗначение(Контекст); + ОбъектПроверки = "каждый элемент проверяемого значения"; + ОписаниеОжидания = Новый Структура(ИмяСвойства, ОжидаемоеЗначение); + + Для Каждого Элемент Из ПроверяемоеЗначение Цикл + + Путь = НормализованныйПутьКСвойству(Элемент, ИмяСвойства, Ложь); + Если Путь = Неопределено Тогда + Сообщение = СтрШаблон("содержит свойство `%1`", ИмяСвойства); + СгенерироватьОшибкуСравнения(Сообщение, ПроверяемоеЗначение, ОписаниеОжидания, ОбъектПроверки); + КонецЕсли; + + ЗначениеСвойства = ЗначениеСвойства(Элемент, Путь); + + Если НЕ ЗначенияРавны(ЗначениеСвойства, ОжидаемоеЗначение) Тогда + Сообщение = СтрШаблон("содержит свойство `%1`, которое равно `%2`", ИмяСвойства, ОжидаемоеЗначение); + СгенерироватьОшибкуСравнения(Сообщение, ПроверяемоеЗначение, ОписаниеОжидания, ОбъектПроверки); + КонецЕсли; + + КонецЦикла; + + Возврат ЮТУтверждения; + +КонецФункции + +// Проверяет элементы установленного значения (или его свойства), хотя бы один из них должен иметь указанное свойство. +// +// Параметры: +// ИмяСвойства - Строка +// ОписаниеПроверки - Строка - Описание конкретной проверки +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция ЛюбойЭлементСодержитСвойство(ИмяСвойства, ОписаниеПроверки = Неопределено) Экспорт + + Контекст = Контекст(); + УстановитьОписаниеПроверки(Контекст, ОписаниеПроверки); + ПроверяемоеЗначение = ПроверяемоеЗначение(Контекст); + ОбъектПроверки = "хоть один элемент проверяемого значения"; + + Найден = Ложь; + Для Каждого Элемент Из ПроверяемоеЗначение Цикл + + Если ЗначениеСодержитСвойство(Элемент, ИмяСвойства) Тогда + Найден = Истина; + Прервать; + КонецЕсли; + + КонецЦикла; + + Если НЕ Найден Тогда + Сообщение = СтрШаблон("содержит свойство `%1`", ИмяСвойства); + СгенерироватьОшибкуСравнения(Сообщение, ПроверяемоеЗначение, ИмяСвойства, ОбъектПроверки); + КонецЕсли; + + Возврат ЮТУтверждения; + +КонецФункции + +// Проверяет элементы установленного значения (или его свойства), +// хотя бы один из них должен иметь указанное свойство, которое равно ожидаемому значению. +// +// Параметры: +// ИмяСвойства - Строка +// ОжидаемоеЗначение - Произвольный - Ожидаемое значение свойства +// ОписаниеПроверки - Строка - Описание конкретной проверки +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция ЛюбойЭлементСодержитСвойствоСоЗначением(ИмяСвойства, ОжидаемоеЗначение, ОписаниеПроверки = Неопределено) Экспорт + + Контекст = Контекст(); + УстановитьОписаниеПроверки(Контекст, ОписаниеПроверки); + ПроверяемоеЗначение = ПроверяемоеЗначение(Контекст); + ОбъектПроверки = "хоть один элемент проверяемого значения"; + + НайденоСвойство = Ложь; + НайденоЗначение = Ложь; + Для Каждого Элемент Из ПроверяемоеЗначение Цикл + + Путь = НормализованныйПутьКСвойству(Элемент, ИмяСвойства, Ложь); + Если Путь = Неопределено Тогда + Продолжить; + КонецЕсли; + + НайденоСвойство = Истина; + ЗначениеСвойства = ЗначениеСвойства(Элемент, Путь); + + Если ЗначенияРавны(ЗначениеСвойства, ОжидаемоеЗначение) Тогда + НайденоЗначение = Истина; + Прервать; + КонецЕсли; + + КонецЦикла; + + ОписаниеОжидания = Новый Структура(ИмяСвойства, ОжидаемоеЗначение); + Если НЕ НайденоСвойство Тогда + Сообщение = СтрШаблон("содержит свойство `%1`", ИмяСвойства); + СгенерироватьОшибкуСравнения(Сообщение, ПроверяемоеЗначение, ОписаниеОжидания, ОбъектПроверки); + ИначеЕсли НЕ НайденоЗначение Тогда + Сообщение = СтрШаблон("содержит свойство `%1`, которое равно `%2`", ИмяСвойства, ОжидаемоеЗначение); + СгенерироватьОшибкуСравнения(Сообщение, ПроверяемоеЗначение, ОписаниеОжидания, ОбъектПроверки); + КонецЕсли; + + Возврат ЮТУтверждения; + +КонецФункции + +// Проверяет установленное значение (или его свойства) на соответствие утверждениям предиката. +// см. ЮТест.Предикат +// +// Параметры: +// Предикат - Массив из см. ЮТФабрика.ВыражениеПредиката - Набор утверждений, см. ЮТПредикаты.Получить +// - см. ЮТФабрика.ВыражениеПредиката +// - ОбщийМодуль - Модуль настройки предикатов, см. ЮТест.Предикат +// ОписаниеПроверки - Строка, Неопределено - Описание конкретной проверки +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция СоответствуетПредикату(Предикат, ОписаниеПроверки = Неопределено) Экспорт + + Контекст = Контекст(); + УстановитьОписаниеПроверки(Контекст, ОписаниеПроверки); + ПроверяемоеЗначение = ПроверяемоеЗначение(Контекст); + + ПараметрыСообщенийОбОшибке = ПараметрыСообщенийОбОшибке(ПроверяемоеЗначение, ОписаниеПроверки); + + РезультатПроверки = ЮТПредикатыСлужебныйКлиентСервер.ПроверитьПредикаты(ПроверяемоеЗначение, Предикат, ПараметрыСообщенийОбОшибке); + + Если НЕ РезультатПроверки.Успешно Тогда + ОбработатьРезультатПроверки(Контекст, РезультатПроверки); + КонецЕсли; + + Возврат ЮТУтверждения; + +КонецФункции + +// Проверяет каждый элемент установленного значения (или его свойства), +// все элементы должны соответствовать утверждениям предиката. +// см. ЮТест.Предикат +// +// Параметры: +// Предикат - Массив из см. ЮТФабрика.ВыражениеПредиката - Набор утверждений, см. ЮТПредикаты.Получить +// - см. ЮТФабрика.ВыражениеПредиката +// - ОбщийМодуль - Модуль настройки предикатов, см. ЮТест.Предикат +// ОписаниеПроверки - Строка, Неопределено - Описание конкретной проверки +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция КаждыйЭлементСоответствуетПредикату(Предикат, ОписаниеПроверки = Неопределено) Экспорт + + Контекст = Контекст(); + УстановитьОписаниеПроверки(Контекст, ОписаниеПроверки); + ПроверяемоеЗначение = ПроверяемоеЗначение(Контекст); + + ПараметрыСообщенийОбОшибке = ПараметрыСообщенийОбОшибке(ПроверяемоеЗначение, ОписаниеПроверки, "каждый элемент проверяемого значения"); + + Для Каждого Элемент Из ПроверяемоеЗначение Цикл + + РезультатПроверки = ЮТПредикатыСлужебныйКлиентСервер.ПроверитьПредикаты(Элемент, Предикат, ПараметрыСообщенийОбОшибке); + Если НЕ РезультатПроверки.Успешно Тогда + ОбработатьРезультатПроверки(Контекст, РезультатПроверки); + КонецЕсли; + + КонецЦикла; + + Возврат ЮТУтверждения; + +КонецФункции + +// Проверяет элементы установленного значения (или его свойства), +// хотя бы один из них должен соответствовать утверждениям предиката. +// см. ЮТест.Предикат +// +// Параметры: +// Предикат - Массив из см. ЮТФабрика.ВыражениеПредиката - Набор утверждений, см. ЮТПредикаты.Получить +// - см. ЮТФабрика.ВыражениеПредиката +// - ОбщийМодуль - Модуль настройки предикатов, см. ЮТест.Предикат +// ОписаниеПроверки - Строка, Неопределено - Описание конкретной проверки +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция ЛюбойЭлементСоответствуетПредикату(Предикат, ОписаниеПроверки = Неопределено) Экспорт + + Контекст = Контекст(); + УстановитьОписаниеПроверки(Контекст, ОписаниеПроверки); + ПроверяемоеЗначение = ПроверяемоеЗначение(Контекст); + + ПараметрыСообщенийОбОшибке = ПараметрыСообщенийОбОшибке(ПроверяемоеЗначение, ОписаниеПроверки); + + Успешно = Ложь; + + Для Каждого Элемент Из ПроверяемоеЗначение Цикл + + РезультатПроверки = ЮТПредикатыСлужебныйКлиентСервер.ПроверитьПредикаты(Элемент, Предикат, ПараметрыСообщенийОбОшибке); + Если РезультатПроверки.Успешно Тогда + Успешно = Истина; + Прервать; + КонецЕсли; + + КонецЦикла; + + Если НЕ Успешно Тогда + Сообщение = ЮТПредикатыСлужебныйКлиентСервер.ПредставлениеПредикатов(Предикат, " и "); + СгенерироватьОшибкуУтверждения(Сообщение, ПроверяемоеЗначение, "один из элементов проверяемого значения"); + КонецЕсли; + + Возврат ЮТУтверждения; + +КонецФункции + +#КонецОбласти + +#Область СлужебныйПрограммныйИнтерфейс + +// Сбросить контекст. +// Используется для принудительного сброса контекста утверждения +Процедура СброситьКонтекст() Экспорт + + ЮТКонтекстСлужебный.УстановитьКонтекстУтверждений(Неопределено); + ЮТРегистрацияОшибокСлужебный.УстановитьКонтекстОшибки(); + +КонецПроцедуры + +// Обработчик события "ПередКаждымТестом" +// +// Параметры: +// ОписаниеСобытия - см. ЮТФабрикаСлужебный.ОписаниеСобытияИсполненияТестов +Процедура ПередКаждымТестом(ОписаниеСобытия) Экспорт + + СброситьКонтекст(); + +КонецПроцедуры + +#КонецОбласти + +#Область СлужебныеПроцедурыИФункции + +#Область Контекст + +// Контекст. +// +// Возвращаемое значение: +// см. НовыйКонтекстУтверждения +Функция Контекст() Экспорт + + //@skip-check constructor-function-return-section + Возврат ЮТКонтекстСлужебный.КонтекстПроверки(); + +КонецФункции + +// Инициализирует контекст утверждений +// +// Параметры: +// ПроверяемоеЗначение - Произвольный - Проверяемое значение +// +// Возвращаемое значение: +// Структура - контекст утверждений: +// * ОбъектПроверки - см. ЮТФабрикаСлужебный.ОписаниеПроверяемогоЗначения +// * ИмяМетода - Строка +// * НормализованныйПутьКСвойству - Неопределено - Не указано свойство +// - Массив из Строка, Число +// * ПараметрыМетода - Неопределено - Не установлены +// - Массив из Произвольный +Функция НовыйКонтекстУтверждения(ПроверяемоеЗначение) + + Контекст = ЮТФабрикаСлужебный.ОписаниеПроверки(ПроверяемоеЗначение); + + Контекст.Вставить("ИмяМетода", ""); + Контекст.Вставить("НормализованныйПутьКСвойству", Неопределено); + Контекст.Вставить("ПараметрыМетода", Неопределено); + + Возврат Контекст; + +КонецФункции + +#КонецОбласти + +Функция ПроверяемоеЗначение(Контекст) + + Если Контекст.ОбъектПроверки.ИмяСвойства <> Неопределено Тогда + Значение = ЗначениеСвойства(Контекст.ОбъектПроверки.Значение, Контекст.НормализованныйПутьКСвойству); + Иначе + Значение = Контекст.ОбъектПроверки.Значение; + КонецЕсли; + + Возврат Значение; + +КонецФункции + +Функция ЗначениеСвойства(Объект, НормализованныйПутьКСвойству) + + Значение = Объект; + Для Каждого Часть Из НормализованныйПутьКСвойству Цикл + + Если ТипЗнч(Значение) = Тип("ХранилищеЗначения") Тогда +#Если ВебКлиент Или ТонкийКлиент Тогда + Значение = ЮТОбщийСлужебныйВызовСервера.ИзХранилищаЗначений(Значение); +#Иначе + Значение = Значение.Получить(); +#КонецЕсли + КонецЕсли; + + Если ТипЗнч(Часть) = Тип("Число") И Часть < 0 И ТипЗнч(Значение) <> Тип("Соответствие") Тогда + Часть = Значение.Количество() + Часть; + КонецЕсли; + + Значение = Значение[Часть]; + + КонецЦикла; + + Возврат Значение; + +КонецФункции + +Функция ЗначенияРавны(Значение1, Значение2) + + Возврат ТипЗнч(Значение1) = ТипЗнч(Значение2) И + (Значение1 = Значение2 ИЛИ СравнитьПоЗначению(Значение1, Значение2)); + +КонецФункции + +Функция НормализованныйПутьКСвойству(Знач Значение, Цепочка, ФиксироватьОшибку = Истина) + + ПутьКСвойству = Новый Массив(); + + ТипПути = ТипЗнч(Цепочка); + + Если ТипПути = Тип("Строка") Тогда + + Части = СтрРазделить(Цепочка, "."); + + ПройденныйПуть = Новый Массив(); + + Для Каждого Часть Из Части Цикл + + ПройденныйПуть.Добавить(Часть); + + ПозицияИндекса = СтрНайти(Часть, "["); + + Если ПозицияИндекса > 0 И СтрЗаканчиваетсяНа(Часть, "]") Тогда + + Если ПозицияИндекса > 1 Тогда + ПутьКСвойству.Добавить(Лев(Часть, ПозицияИндекса - 1)); + КонецЕсли; + + Пока ПозицияИндекса > 0 Цикл + + ЗакрывающаяПозиция = СтрНайти(Часть, "]", , ПозицияИндекса); + ИндексСтрокой = Сред(Часть, ПозицияИндекса + 1, ЗакрывающаяПозиция - ПозицияИндекса - 1); + Индекс = Число(ИндексСтрокой); + ПутьКСвойству.Добавить(Индекс); + + ПозицияИндекса = СтрНайти(Часть, "[", , ЗакрывающаяПозиция); + + КонецЦикла; + + Иначе + + ПутьКСвойству.Добавить(Часть); + + КонецЕсли; + + КонецЦикла; + + Иначе + + ПутьКСвойству.Добавить(Цепочка); + + КонецЕсли; + + ПройденныйПуть = Новый Массив(); + + Для Каждого Часть Из ПутьКСвойству Цикл + + ПройденныйПуть.Добавить(Часть); + + Если ТипЗнч(Значение) = Тип("ХранилищеЗначения") Тогда + Значение = Значение.Получить(); + КонецЕсли; + + Попытка + ЕстьСвойство = ЗначениеИмеетСвойство(Значение, Часть); + Исключение + ЕстьСвойство = Ложь; + КонецПопытки; + + Если ЕстьСвойство Тогда + Значение = Значение[Часть]; + ИначеЕсли ФиксироватьОшибку Тогда + ПутьСвойства = СтрСоединить(ПройденныйПуть, "."); + СгенерироватьОшибкуСравнения(СтрШаблон("содержит свойство `%1`", ПутьСвойства), Значение, Цепочка); + Иначе + Возврат Неопределено; + КонецЕсли; + + КонецЦикла; + + Возврат ПутьКСвойству; + +КонецФункции + +Функция ЗначениеСодержитСвойство(Знач Значение, Знач ИмяСвойства) + + Возврат НормализованныйПутьКСвойству(Значение, ИмяСвойства, Ложь) <> Неопределено; + +КонецФункции + +Функция ЗначениеИмеетСвойство(Значение, Свойство) + + Результат = Ложь; + ТипЗначения = ТипЗнч(Значение); + + Если ЮТТипыДанныхСлужебный.ЭтоСтруктура(ТипЗначения) Тогда + + Результат = Значение.Свойство(Свойство); + + ИначеЕсли ЮТТипыДанныхСлужебный.ЭтоСоответствие(ТипЗначения) Тогда + + Для Каждого КлючЗначение Из Значение Цикл + + Если КлючЗначение.Ключ = Свойство И ТипЗнч(КлючЗначение.Ключ) = ТипЗнч(Свойство) Тогда + Результат = Истина; + Прервать; + КонецЕсли; + + КонецЦикла; + + ИначеЕсли ТипЗнч(Свойство) = Тип("Число") Тогда + + Если Свойство < 0 Тогда + Свойство = Значение.Количество() + Свойство; + КонецЕсли; + Результат = Свойство >= 0 И Значение.Количество() > Свойство; + + Иначе + + Результат = ЮТОбщий.ПеременнаяСодержитСвойство(Значение, Свойство); + + КонецЕсли; + + Возврат Результат; + +КонецФункции + +Функция ДлинаЗначения(ПроверяемоеЗначение) + + ТипПроверяемогоЗначения = ТипЗнч(ПроверяемоеЗначение); + + Если ТипПроверяемогоЗначения = Тип("Строка") ИЛИ ТипПроверяемогоЗначения = Тип("ФорматированнаяСтрока") Тогда + + ФактическаяДлина = СтрДлина(ПроверяемоеЗначение); + + Иначе + + Попытка + ФактическаяДлина = ПроверяемоеЗначение.Количество(); + Исключение + ФактическаяДлина = Неопределено; + КонецПопытки; + + КонецЕсли; + + Возврат ФактическаяДлина; + +КонецФункции + +Функция ВызватьМетод(Модуль, ИмяМетода, ПараметрыМетода, ВТранзакции) + +#Если ВебКлиент Тогда + ВызватьИсключение ЮТИсключения.МетодНеДоступен("ЮТУтверждения.ВызватьМетод"); +#Иначе + Если НЕ ЗначениеЗаполнено(ИмяМетода) Тогда + ВызватьИсключение "ИмяМетода не заполнено в контексте. Воспользуйтесь предварительно методом интерфейса `Метод(ИмяМетода)`"; + КонецЕсли; + +#Если НЕ Сервер Тогда + Если ВТранзакции Тогда + ВызватьИсключение "Использование транзакции доступно только на сервере (толстом клиенте)"; + КонецЕсли; +#КонецЕсли + + Если Модуль <> Неопределено Тогда + ПолноеИмяМетода = СтрШаблон("Объект.%1", ИмяМетода); + Иначе + ПолноеИмяМетода = СтрШаблон("%1", ИмяМетода); + КонецЕсли; + + Результат = Новый Структура("ИсключениеВозникло, ТекстИсключения", Ложь); + +#Если Сервер Тогда + Если ВТранзакции Тогда + Если ТранзакцияАктивна() Тогда + ВызватьИсключение "Использование транзакции внутри транзакции при проверке метода недопустимо"; + КонецЕсли; + + НачатьТранзакцию(); // BSLLS:PairingBrokenTransaction-off BSLLS:BeginTransactionBeforeTryCatch-off + Ошибка = ЮТМетодыСлужебный.ВыполнитьМетод(ПолноеИмяМетода, ПараметрыМетода, Модуль); + ОтменитьТранзакцию(); // BSLLS:WrongUseOfRollbackTransactionMethod-off + Иначе + Ошибка = ЮТМетодыСлужебный.ВыполнитьМетод(ПолноеИмяМетода, ПараметрыМетода, Модуль); + КонецЕсли; +#Иначе + Ошибка = ЮТМетодыСлужебный.ВыполнитьМетод(ПолноеИмяМетода, ПараметрыМетода, Модуль); +#КонецЕсли + + Если Ошибка <> Неопределено Тогда + Результат.ТекстИсключения = КраткоеПредставлениеОшибки(Ошибка); + Результат.ИсключениеВозникло = Истина; + КонецЕсли; + + Возврат Результат; +#КонецЕсли + +КонецФункции + +#Область ПроверкаТипов + +Процедура ПроверитьТипЗначения(Контекст, + Значение, + Знач ОжидаемыйТип, + Описание = "ожидаемого значения", + ЕслиУстановлен = Ложь, + Суффикс = Неопределено) + + Если ЕслиУстановлен И Значение = Неопределено Тогда + Возврат; + КонецЕсли; + + Соответствует = ЮТПроверкиСлужебный.ТипЗначенияСоответствует(Значение, ОжидаемыйТип); + + Если НЕ Соответствует Тогда + ТекстОшибки = СтрШаблон("Не верный тип %1 (`%2`), должен быть `%3`%4", + Описание, + ТипЗнч(Значение), + ОжидаемыйТип, + Суффикс); + ЮТРегистрацияОшибокСлужебный.СгенерироватьОшибкуВыполнения(ТекстОшибки, Контекст); + КонецЕсли; + +КонецПроцедуры + +#КонецОбласти + +Функция СравнитьПоЗначению(Значение1, Значение2) + + Попытка + СтрокаСравнения1 = ЮТОбщий.СтрокаJSON(Значение1); + СтрокаСравнения2 = ЮТОбщий.СтрокаJSON(Значение2); + Возврат СтрокаСравнения1 = СтрокаСравнения2; + Исключение + Возврат Ложь; + КонецПопытки; + +КонецФункции + +Процедура УстановитьОписаниеПроверки(Контекст, ОписаниеПроверки) + + Контекст.ОписаниеПроверки = ОписаниеПроверки; + +КонецПроцедуры + +Процедура СравнитьЗначения(Контекст, ОжидаемоеЗначение, Реверс, Сообщение) + + Попытка + ПроверяемоеЗначение = ПроверяемоеЗначение(Контекст); + Результат = ЗначенияРавны(ПроверяемоеЗначение, ОжидаемоеЗначение); + Исключение + ЮТРегистрацияОшибокСлужебный.СгенерироватьОшибкуВыполнения(ИнформацияОбОшибке(), Контекст); + КонецПопытки; + + ОбработатьРезультатСравнения(Результат, Сообщение, Реверс, ПроверяемоеЗначение, ОжидаемоеЗначение); + +КонецПроцедуры + +Процедура ПроверитьСуществование(Контекст, Реверс) + Попытка + ПроверяемоеЗначение = ПроверяемоеЗначение(Контекст); + Результат = ПроверяемоеЗначение <> Null И ПроверяемоеЗначение <> Неопределено; + Исключение + ЮТРегистрацияОшибокСлужебный.СгенерироватьОшибкуВыполнения(ИнформацияОбОшибке(), Контекст); + КонецПопытки; + + ОбработатьРезультатСравнения(Результат, "существует", Реверс, ПроверяемоеЗначение, Неопределено); + +КонецПроцедуры + +Функция ДлинаПроверяемогоЗначения(Контекст) + + Попытка + ПроверяемоеЗначение = ПроверяемоеЗначение(Контекст); + ФактическаяДлина = ДлинаЗначения(ПроверяемоеЗначение); + Исключение + ЮТРегистрацияОшибокСлужебный.СгенерироватьОшибкуВыполнения(ИнформацияОбОшибке(), Контекст); + КонецПопытки; + + Если ФактическаяДлина = Неопределено Тогда + ТекстОшибки = СтрШаблон("Тип проверяемого значения `%1` не обрабатывается утверждением", ТипЗнч(ПроверяемоеЗначение)); + ЮТРегистрацияОшибокСлужебный.СгенерироватьОшибкуВыполнения(ТекстОшибки, Контекст); + КонецЕсли; + + Возврат ФактическаяДлина; + +КонецФункции + +Процедура ОбработатьРезультатСравнения(Знач Результат, Знач Сообщение, Реверс, ПроверяемоеЗначение, ОжидаемоеЗначение) + + Если Реверс Тогда + Результат = НЕ Результат; + Сообщение = "не " + Сообщение; + КонецЕсли; + + Если НЕ Результат Тогда + СгенерироватьОшибкуСравнения(Сообщение, ПроверяемоеЗначение, ОжидаемоеЗначение); + КонецЕсли; + +КонецПроцедуры + +Процедура ПроверитьМежду(Контекст, НачалоИнтервала, ОкончаниеИнтервала, ВключаяНачало, ВключаяОкончание) + + ПроверяемоеЗначение = ПроверяемоеЗначение(Контекст); + + ТипЗначения = ТипЗнч(ПроверяемоеЗначение); + + Суффикс = ". Он должен совпадать с типом проверяемого значения"; + ПроверитьТипЗначения(Контекст, НачалоИнтервала, ТипЗначения, "левой границы интервала", , Суффикс); + ПроверитьТипЗначения(Контекст, ОкончаниеИнтервала, ТипЗначения, "правой границы интервала", , Суффикс); + + Если НачалоИнтервала > ОкончаниеИнтервала Тогда + ТекстОшибки = СтрШаблон("Не корректно задан интервал, левая граница (%1) не должна быть больше правой (%2)", + НачалоИнтервала, + ОкончаниеИнтервала); + ЮТРегистрацияОшибокСлужебный.СгенерироватьОшибкуВыполнения(ТекстОшибки, Контекст); + КонецЕсли; + Результат = Истина; + + Если ВключаяНачало Тогда + Результат = НачалоИнтервала <= ПроверяемоеЗначение; + Иначе + Результат = НачалоИнтервала < ПроверяемоеЗначение; + КонецЕсли; + + Если ВключаяОкончание Тогда + Результат = Результат И ПроверяемоеЗначение <= ОкончаниеИнтервала; + Иначе + Результат = Результат И ПроверяемоеЗначение < ОкончаниеИнтервала; + КонецЕсли; + + Если НЕ Результат Тогда + Интервал = СтрШаблон("%1%2; %3%4", + ?(ВключаяНачало, "[", "("), + НачалоИнтервала, + ОкончаниеИнтервала, + ?(ВключаяОкончание, "]", ")")); + Сообщение = "находится в интервале " + Интервал; + СгенерироватьОшибкуСравнения(Сообщение, ПроверяемоеЗначение, Интервал); + КонецЕсли; + +КонецПроцедуры + +Процедура ПроверитьЗаполненностьЗначения(Контекст, Значение, Описание) + + Если НЕ ЗначениеЗаполнено(Значение) Тогда + ТекстОшибки = СтрШаблон("Ожидали, что %1 заполнено, но это не так", Описание); + ЮТРегистрацияОшибокСлужебный.СгенерироватьОшибкуВыполнения(ТекстОшибки, Контекст); + КонецЕсли; +КонецПроцедуры + +Процедура ОбъектыРавны(Объект, ОбъектЭталон) + + Ключи = ЮТКоллекции.ВыгрузитьЗначения(ОбъектЭталон, "Ключ"); + ТипЗначения = ТипЗнч(Объект); + + ЭтоСоответствие = ЮТТипыДанныхСлужебный.ЭтоСоответствие(ТипЗначения); + ЭтоСтруктура = ЮТТипыДанныхСлужебный.ЭтоСтруктура(ТипЗначения); + + ЗначениеОтсутствующегоРеквизита = Новый УникальныйИдентификатор(); + + Если НЕ ЭтоСтруктура И НЕ ЭтоСоответствие Тогда + СтруктураОбъекта = Новый Структура(СтрСоединить(Ключи, ",")); + Для Каждого Ключ Из Ключи Цикл + СтруктураОбъекта[Ключ] = ЗначениеОтсутствующегоРеквизита; + КонецЦикла; + ЗаполнитьЗначенияСвойств(СтруктураОбъекта, Объект); + Иначе + СтруктураОбъекта = Объект; + КонецЕсли; + + Для Каждого Ключ Из Ключи Цикл + + Если НЕ ЭтоСоответствие И (НЕ СтруктураОбъекта.Свойство(Ключ) ИЛИ СтруктураОбъекта[Ключ] = ЗначениеОтсутствующегоРеквизита) Тогда + Сообщение = СтрШаблон("не содержат свойство '%1'", Ключ); + СгенерироватьОшибкуСравнения(Сообщение, СтруктураОбъекта, ОбъектЭталон); + КонецЕсли; + + Если НЕ ЗначенияРавны(Объект[Ключ], ОбъектЭталон[Ключ]) Тогда + Сообщение = СтрШаблон("имеет свойство '%1', которое равно `%2`", Ключ, ОбъектЭталон[Ключ]); + СгенерироватьОшибкуСравнения(Сообщение, СтруктураОбъекта, ОбъектЭталон); + КонецЕсли; + + КонецЦикла; + +КонецПроцедуры + +Процедура ОбработатьРезультатПроверки(Контекст, Результат) + + Если НЕ Результат.Успешно Тогда + + Для Каждого Сообщение Из Результат.Сообщения Цикл + + Если ТипЗнч(Сообщение) = Тип("Структура") Тогда + ЮТРегистрацияОшибокСлужебный.УстановитьДанныеОшибкиСравнения(Сообщение.ПроверяемоеЗначение, Сообщение.ОжидаемоеЗначение); + + ТекстИсключения = СтрШаблон("%1 <%2>", ЮТРегистрацияОшибокСлужебный.ПрефиксОшибкиУтверждений(), Сообщение.Сообщение); + ВызватьИсключение ТекстИсключения; + Иначе + ЮТРегистрацияОшибокСлужебный.СгенерироватьОшибкуВыполнения(Сообщение, Контекст); + КонецЕсли; + + КонецЦикла; + + ВызватьИсключение "Провальный результат проверки не содержит сообщения"; + + КонецЕсли; + +КонецПроцедуры + +Функция ПараметрыСообщенийОбОшибке(ПроверяемоеЗначение, ОписаниеПроверки, ОбъектПроверки = "проверяемое значение") + + Контекст = Контекст(); + ПолноеОписаниеПроверки = ЮТСтроки.ДобавитьСтроку(Контекст.ПрефиксОшибки, ОписаниеПроверки, " "); + ПредставлениеЗначения = СтрШаблон("`%1`", ПроверяемоеЗначение); + + Возврат ЮТПредикатыСлужебныйКлиентСервер.ПараметрыСообщенийОбОшибке(ПолноеОписаниеПроверки, ОбъектПроверки, ПредставлениеЗначения); + +КонецФункции + +// Вызывает ошибку проверки утверждений +// При этом сохраняет в контекст состояние, для дальнейшей обработки +// +// Параметры: +// Сообщение - Строка +// ПроверяемоеЗначение - Произвольный +// ОбъектПроверки - Строка - Человекочитаемое описание проверяемого значения +Процедура СгенерироватьОшибкуУтверждения(Сообщение, ПроверяемоеЗначение, ОбъектПроверки = "проверяемое значение") + + Контекст = Контекст(); + ЮТРегистрацияОшибокСлужебный.СгенерироватьОшибкуУтверждения(Контекст, Сообщение, ПроверяемоеЗначение, ОбъектПроверки); + +КонецПроцедуры + +Процедура СгенерироватьОшибкуСравнения(Сообщение, ФактическоеЗначение, ОжидаемоеЗначение, ОбъектПроверки = "проверяемое значение") + + Контекст = Контекст(); + ЮТРегистрацияОшибокСлужебный.СгенерироватьОшибкуСравнения(Контекст, Сообщение, ФактическоеЗначение, ОжидаемоеЗначение, ОбъектПроверки); + +КонецПроцедуры + +#Область Предикаты + +Процедура ПроверитьПредикат(Выражение, ОжидаемоеЗначение, ОписаниеПроверки, ПараметрыСравнения = Неопределено) + + Контекст = Контекст(); + Предикат = ЮТФабрика.ВыражениеПредиката(Выражение, Контекст.ОбъектПроверки.ИмяСвойства, ОжидаемоеЗначение); + + ПолноеОписаниеПроверки = ЮТСтроки.ДобавитьСтроку(Контекст.ПрефиксОшибки, ОписаниеПроверки, " "); + + ПараметрыСообщенийОбОшибке = ЮТПредикатыСлужебныйКлиентСервер.ПараметрыСообщенийОбОшибке(ПолноеОписаниеПроверки, , Контекст.ОбъектПроверки.Представление); + Результат = ЮТПредикатыСлужебныйКлиентСервер.ПроверитьПредикаты(Контекст.ОбъектПроверки.Значение, Предикат, ПараметрыСообщенийОбОшибке, ПараметрыСравнения); + + ОбработатьРезультатПроверкиПредиката(Результат); + +КонецПроцедуры + +Процедура ОбработатьРезультатПроверкиПредиката(Результат) + + Если НЕ Результат.Успешно Тогда + + Для Каждого Сообщение Из Результат.Сообщения Цикл + + Если ТипЗнч(Сообщение) = Тип("Структура") Тогда + ЮТРегистрацияОшибокСлужебный.УстановитьДанныеОшибкиСравнения(Сообщение.ПроверяемоеЗначение, Сообщение.ОжидаемоеЗначение); + + ТекстИсключения = СтрШаблон("%1 <%2>", ЮТРегистрацияОшибокСлужебный.ПрефиксОшибкиУтверждений(), Сообщение.Сообщение); + ВызватьИсключение ТекстИсключения; + Иначе + ЮТРегистрацияОшибокСлужебный.СгенерироватьОшибкуВыполнения(Сообщение); + КонецЕсли; + + КонецЦикла; + + ВызватьИсключение "Провальный результат проверки не содержит сообщения"; + + КонецЕсли; + +КонецПроцедуры + +Процедура ПроверитьСодержаниеПредиката(Предикат, ОписаниеПроверки, Реверс) + + Контекст = Контекст(); + УстановитьОписаниеПроверки(Контекст, ОписаниеПроверки); + ПроверяемоеЗначение = ПроверяемоеЗначение(Контекст); + + ПараметрыСообщенийОбОшибке = ПараметрыСообщенийОбОшибке(ПроверяемоеЗначение, ОписаниеПроверки); + + Успешно = Ложь; + + Для Каждого Элемент Из ПроверяемоеЗначение Цикл + + РезультатПроверки = ЮТПредикатыСлужебныйКлиентСервер.ПроверитьПредикаты(Элемент, Предикат, ПараметрыСообщенийОбОшибке); + Если РезультатПроверки.Успешно Тогда + Успешно = Истина; + Прервать; + КонецЕсли; + + КонецЦикла; + + Если Реверс Тогда + Успешно = НЕ Успешно; + КонецЕсли; + + Если НЕ Успешно Тогда + Сообщение = "содержит элемент, значение которого " + ЮТПредикатыСлужебныйКлиентСервер.ПредставлениеПредикатов(Предикат, " и "); + + Если Реверс Тогда + Сообщение = "не " + Сообщение; + КонецЕсли; + + СгенерироватьОшибкуУтверждения(Сообщение, ПроверяемоеЗначение); + КонецЕсли; + +КонецПроцедуры + +#КонецОбласти + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТУтвержденияИБ.xml b/src/cfe/YAXUnit/CommonModules/ЮТУтвержденияИБ.xml new file mode 100644 index 0000000..b0c41c1 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТУтвержденияИБ.xml @@ -0,0 +1,23 @@ + + + + + ЮТУтвержденияИБ + + + ru + Утверждения ИБ + + + + false + true + true + false + true + false + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТУтвержденияИБ/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТУтвержденияИБ/Ext/Module.bsl new file mode 100644 index 0000000..c008daf --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТУтвержденияИБ/Ext/Module.bsl @@ -0,0 +1,300 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +/////////////////////////////////////////////////////////////////// +// Предоставляет методы для формирования утверждений проверяющих данные информационной базы. +// +// Например: +// +// ```bsl +// ЮТест.ОжидаетЧтоТаблицаБазы("Справочник.Товары") +// .СодержитЗаписи(); +// ЮТест.ОжидаетЧтоТаблицаБазы("РегистрСведений.КурсыВалют") +// .СодержитЗаписи(ЮТест.Предикат() +// .Реквизит("Валюта").Равно(ДанныеРегистра.Валюта)); +// ``` +/////////////////////////////////////////////////////////////////// +#Область ПрограммныйИнтерфейс + +// Инициализирует модуль для проверки утверждений. +// +// * Запоминает/устанавливает имя проверяемой таблицы +// * Запоминает описание. +// +// Параметры: +// ИмяТаблицы - Строка - Имя проверяемой таблицы, например, Справочник.Товары, РегистрНакопления.ТоварыНаСкладах +// ОписаниеПроверки - Строка - Описание проверки, которое будет выведено при возникновении ошибки +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +// Примеры +// ЮТест.ОжидаетЧтоТаблицаБазы("Справочник.Товары").СодержитЗаписи(); +// +Функция ЧтоТаблица(ИмяТаблицы, ОписаниеПроверки = "") Экспорт + + Контекст = НовыйКонтекст(ИмяТаблицы); + Контекст.ПрефиксОшибки = ОписаниеПроверки; + + ЮТКонтекстСлужебный.УстановитьЗначениеКонтекста(ИмяКонтекста(), Контекст); + + Возврат ЮТУтвержденияИБ; + +КонецФункции + +// Проверяет наличие в таблице записей удовлетворяющих условиям +// +// Параметры: +// Предикат - ОбщийМодуль - Модуль настройки предикатов, см. ЮТест.Предикат +// - Массив из см. ЮТФабрика.ВыражениеПредиката - Набор условий, см. ЮТПредикаты.Получить +// - см. ЮТФабрика.ВыражениеПредиката +// - Неопределено - Проверит, что таблица не пустая +// ОписаниеУтверждения - Строка - Описание конкретного утверждения +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция СодержитЗаписи(Знач Предикат = Неопределено, Знач ОписаниеУтверждения = Неопределено) Экспорт + + Контекст = Контекст(); + УстановитьОписаниеПроверки(Контекст, ОписаниеУтверждения); + Результат = ЮТЗапросы.ТаблицаСодержитЗаписи(Контекст.ОбъектПроверки.Значение, Предикат); + + Если Не Результат Тогда + Контекст = Контекст(); + СгенерироватьОшибкуУтверждения(Контекст, Предикат, "содержит записи"); + КонецЕсли; + + Возврат ЮТУтвержденияИБ; + +КонецФункции + +// Проверяет отсутствие в таблице записей удовлетворяющих условиям +// +// Параметры: +// Предикат - ОбщийМодуль - Условия сформированные с использованием см. ЮТест.Предикат +// - Массив из см. ЮТФабрика.ВыражениеПредиката - Набор условий, см. ЮТПредикаты.Получить +// - см. ЮТФабрика.ВыражениеПредиката +// - Неопределено - Проверит, что таблица пустая +// ОписаниеУтверждения - Строка - Описание конкретного утверждения +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция НеСодержитЗаписи(Знач Предикат = Неопределено, Знач ОписаниеУтверждения = Неопределено) Экспорт + + Контекст = Контекст(); + УстановитьОписаниеПроверки(Контекст, ОписаниеУтверждения); + Результат = НЕ ЮТЗапросы.ТаблицаСодержитЗаписи(Контекст.ОбъектПроверки.Значение, Предикат); + + Если Не Результат Тогда + Контекст = Контекст(); + СгенерироватьОшибкуУтверждения(Контекст, Предикат, "не содержит записи"); + КонецЕсли; + + Возврат ЮТУтвержденияИБ; + +КонецФункции + +// Проверяет наличие в таблице записей с указанным наименованием +// +// Параметры: +// ОжидаемоеНаименование - Строка +// ПроверятьПометкуУдаления - Булево - Проверять пометку удаления. +// + `Истина` - Подбираются только непомеченные на удаление записи. +// + `Ложь` - пометка на удаление игнорируется +// +// ОписаниеУтверждения - Строка - Описание конкретного утверждения +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция СодержитЗаписиСНаименованием(ОжидаемоеНаименование, ПроверятьПометкуУдаления = Истина, ОписаниеУтверждения = Неопределено) Экспорт + + Условия = ПредикатПоискаПоРеквизиту("Наименование", ОжидаемоеНаименование, ПроверятьПометкуУдаления); + Возврат СодержитЗаписи(Условия, ОписаниеУтверждения); + +КонецФункции + +// Проверяет наличие в таблице записей с указанным кодом +// +// Параметры: +// ОжидаемыйКод - Строка +// ПроверятьПометкуУдаления - Булево - Проверять пометку удаления. +// + `Истина` - Подбираются только непомеченные на удаление записи. +// + `Ложь` - пометка на удаление игнорируется +// +// ОписаниеУтверждения - Строка - Описание конкретного утверждения +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция СодержитЗаписиСКодом(ОжидаемыйКод, ПроверятьПометкуУдаления = Истина, ОписаниеУтверждения = Неопределено) Экспорт + + Условия = ПредикатПоискаПоРеквизиту("Код", ОжидаемыйКод, ПроверятьПометкуУдаления); + Возврат СодержитЗаписи(Условия, ОписаниеУтверждения); + +КонецФункции + +// Проверяет наличие в таблице записей с указанным номером +// +// Параметры: +// ОжидаемыйНомер - Строка +// ПроверятьПометкуУдаления - Булево - Проверять пометку удаления. +// + `Истина` - Подбираются только непомеченные на удаление записи. +// + `Ложь` - пометка на удаление игнорируется +// +// ОписаниеУтверждения - Строка - Описание конкретного утверждения +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция СодержитЗаписиСНомером(ОжидаемыйНомер, ПроверятьПометкуУдаления = Истина, ОписаниеУтверждения = Неопределено) Экспорт + + Условия = ПредикатПоискаПоРеквизиту("Номер", ОжидаемыйНомер, ПроверятьПометкуУдаления); + Возврат СодержитЗаписи(Условия, ОписаниеУтверждения); + +КонецФункции + +// Проверяет отсутствие в таблице записей с указанным наименованием +// +// Параметры: +// ОжидаемоеНаименование - Строка +// ПроверятьПометкуУдаления - Булево - Проверять пометку удаления. +// + `Истина` - Подбираются только непомеченные на удаление записи. +// + `Ложь` - пометка на удаление игнорируется +// +// ОписаниеУтверждения - Строка - Описание конкретного утверждения +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция НеСодержитЗаписиСНаименованием(ОжидаемоеНаименование, ПроверятьПометкуУдаления = Истина, ОписаниеУтверждения = Неопределено) Экспорт + + Условия = ПредикатПоискаПоРеквизиту("Наименование", ОжидаемоеНаименование, ПроверятьПометкуУдаления); + Возврат НеСодержитЗаписи(Условия, ОписаниеУтверждения); + +КонецФункции + +// Проверяет отсутствие в таблице записей с указанным кодом +// +// Параметры: +// ОжидаемыйКод - Строка +// ПроверятьПометкуУдаления - Булево - Проверять пометку удаления. +// + `Истина` - Подбираются только непомеченные на удаление записи. +// + `Ложь` - пометка на удаление игнорируется +// +// ОписаниеУтверждения - Строка - Описание конкретного утверждения +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция НеСодержитЗаписиСКодом(ОжидаемыйКод, ПроверятьПометкуУдаления = Истина, ОписаниеУтверждения = Неопределено) Экспорт + + Условия = ПредикатПоискаПоРеквизиту("Код", ОжидаемыйКод, ПроверятьПометкуУдаления); + Возврат НеСодержитЗаписи(Условия, ОписаниеУтверждения); + +КонецФункции + +// Проверяет отсутствие в таблице записей с указанным номером +// +// Параметры: +// ОжидаемыйНомер - Строка +// ПроверятьПометкуУдаления - Булево - Проверять пометку удаления. +// + `Истина` - Подбираются только непомеченные на удаление записи. +// + `Ложь` - пометка на удаление игнорируется +// +// ОписаниеУтверждения - Строка - Описание конкретного утверждения +// +// Возвращаемое значение: +// ОбщийМодуль - Этот модуль для замыкания +Функция НеСодержитЗаписиСНомером(ОжидаемыйНомер, ПроверятьПометкуУдаления = Истина, ОписаниеУтверждения = Неопределено) Экспорт + + Условия = ПредикатПоискаПоРеквизиту("Номер", ОжидаемыйНомер, ПроверятьПометкуУдаления); + Возврат НеСодержитЗаписи(Условия, ОписаниеУтверждения); + +КонецФункции + +#КонецОбласти + +#Область СлужебныеПроцедурыИФункции + +#Область Контекст + +// Контекст. +// +// Возвращаемое значение: +// см. НовыйКонтекст +Функция Контекст() + + //@skip-check constructor-function-return-section + Возврат ЮТКонтекстСлужебный.ЗначениеКонтекста(ИмяКонтекста()); + +КонецФункции + +// Инициализирует контекст +// +// Параметры: +// ИмяТаблицы - Строка +// +// Возвращаемое значение: +// см. ЮТФабрикаСлужебный.ОписаниеПроверки +Функция НовыйКонтекст(ИмяТаблицы) + + Контекст = ЮТФабрикаСлужебный.ОписаниеПроверки(ИмяТаблицы); + + Возврат Контекст; + +КонецФункции + +Функция ИмяКонтекста() + + Возврат "КонтекстУтвержденияИБ"; + +КонецФункции + +#КонецОбласти + +Процедура СгенерироватьОшибкуУтверждения(Контекст, Предикат, Сообщение) + + Если Предикат <> Неопределено Тогда + ПредставлениеПредиката = ЮТПредикатыСлужебныйКлиентСервер.ПредставлениеПредикатов(Предикат, ", ", "`%1`"); + КонецЕсли; + + Если ЗначениеЗаполнено(ПредставлениеПредиката) Тогда + СообщениеОбОшибке = СтрШаблон("%1 с %2", Сообщение, ПредставлениеПредиката); + Иначе + СообщениеОбОшибке = Сообщение; + КонецЕсли; + + ЮТРегистрацияОшибокСлужебный.СгенерироватьОшибкуУтверждения(Контекст, СообщениеОбОшибке, Неопределено, "проверяемая таблица"); + +КонецПроцедуры + +Процедура УстановитьОписаниеПроверки(Контекст, ОписаниеПроверки) + + Контекст.ОписаниеПроверки = ОписаниеПроверки; + +КонецПроцедуры + +Функция ПредикатПоискаПоРеквизиту(ИмяРеквизита, ЗначениеРеквизита, ПроверятьПометкуУдаления) + + Условия = ЮТПредикаты.Инициализировать() + .Реквизит(ИмяРеквизита).Равно(ЗначениеРеквизита); + + Если ПроверятьПометкуУдаления Тогда + Условия.Реквизит("ПометкаУдаления").Равно(Ложь); + КонецЕсли; + + Возврат Условия; + +КонецФункции + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТФабрика.xml b/src/cfe/YAXUnit/CommonModules/ЮТФабрика.xml new file mode 100644 index 0000000..cad0590 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТФабрика.xml @@ -0,0 +1,23 @@ + + + + + ЮТФабрика + + + ru + Фабрика + + + + false + true + true + false + true + false + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТФабрика/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТФабрика/Ext/Module.bsl new file mode 100644 index 0000000..ee36eba --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТФабрика/Ext/Module.bsl @@ -0,0 +1,283 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область ПрограммныйИнтерфейс + +#Область Перечисления +// КонтекстыВызова +// Возвращает перечисление возможных контекстов вызова +// Возвращаемое значение: +// ФиксированнаяСтруктура - Контексты вызова: +// * КлиентОбычноеПриложение - Строка +// * КлиентУправляемоеПриложение - Строка +// * Сервер - Строка +// * ВызовСервера - Строка +Функция КонтекстыВызова() Экспорт + + Контексты = Новый Структура(); + + Контексты.Вставить("КлиентОбычноеПриложение", "КлиентОбычноеПриложение"); + Контексты.Вставить("КлиентУправляемоеПриложение", "КлиентУправляемоеПриложение"); + Контексты.Вставить("Сервер", "Сервер"); + Контексты.Вставить("ВызовСервера", "ВызовСервера"); + + // TODO Подозреваю нужно добавить web клиент + + Возврат Новый ФиксированнаяСтруктура(Контексты); + +КонецФункции + +// КонтекстыИсполнения +// Возвращает перечисление возможных контекстов исполнения тестов +// +// Возвращаемое значение: +// ФиксированнаяСтруктура - Контексты исполнения: +// * Клиент - Строка +// * Сервер - Строка +Функция КонтекстыИсполнения() Экспорт + + Контексты = Новый Структура(); + + Контексты.Вставить("Клиент", "Клиент"); + Контексты.Вставить("Сервер", "Сервер"); + + Возврат Новый ФиксированнаяСтруктура(Контексты); + +КонецФункции + +// Возвращает перечисление возможных статусов выполнения теста, жизненный цикл теста +// +// Возвращаемое значение: +// ФиксированнаяСтруктура - Статусы исполнения теста: +// * Ожидание- Строка - Тест не выполнялся +// * Исполнение- Строка - Тест выполняется в данный момент +// * Успешно- Строка - Тест успешно пройден +// * Ошибка- Строка - Тест упал с ошибкой выполнения +// * Сломан- Строка - Тест упал на проверках утверждений +// * Пропущен- Строка - Тест пропущен по каким либо причинам +// * НеРеализован- Строка - Тест не реализован +Функция СтатусыИсполненияТеста() Экспорт + + Статусы = Новый Структура(); + + Статусы.Вставить("Ожидание", "Ожидание"); + Статусы.Вставить("Исполнение", "Исполнение"); + Статусы.Вставить("Успешно", "Успешно"); + Статусы.Вставить("Ошибка", "Ошибка"); + Статусы.Вставить("Сломан", "Сломан"); + Статусы.Вставить("Пропущен", "Пропущен"); + Статусы.Вставить("НеРеализован", "НеРеализован"); + + Возврат Новый ФиксированнаяСтруктура(Статусы); + +КонецФункции + +// Возвращает перечисление возможные уровнией исполнения тестрв. +// +// Возвращаемое значение: +// ФиксированнаяСтруктура - Уровни исполнения: +// * Модуль - Строка +// * НаборТестов - Строка +// * Тест - Строка +Функция УровниИсполнения() Экспорт + + Уровни = Новый Структура; + Уровни.Вставить("Модуль", "Модуль"); + Уровни.Вставить("НаборТестов", "НаборТестов"); + Уровни.Вставить("Тест", "Тест"); + + Возврат Новый ФиксированнаяСтруктура(Уровни); + +КонецФункции + +#КонецОбласти + +// ПараметрыЗапуска +// Набор параметров подсистемы тестирования. +// Параметры на английском, чтобы не держать несколько реализаций чтения и обработки параметров +// +// Возвращаемое значение: +// Структура - Параметры: +// * ВыполнятьМодульноеТестирование - Булево - Признак необходимости выполнения тестов +// * reportPath - Строка - Файл или каталог сохранения отчета о тестировании +// * filter - см. ПараметрыФильтрации +// * settings - см. НастройкиВыполнения +// * closeAfterTests - Булево - Признак необходимости закрытия приложения по окончании прогона +// * reportFormat - Строка - Формат отчета о тестировании. +// Модули реализующие различные форматы отчетов собраны в подсистеме ЮТФормированиеОтчета +// * logging - см. ПараметрыЛогирования +// * showReport - Булево - Признак необходмости отобразить отчет в 1с по окончании тестирования +// * exitCode - Строка - Путь к файлу, в который будет записан коды выхода +// * ПодключатьВнешниеКомпоненты - Булево - Выполнять установку и подключение внешних компонент при старте. +// Если выключено и включен запрет синхронных вызовов, то компоненты не будут доступы в тонком клиенте. +// Если выключено и разрешены синхронные вызовы, то компоненты можно установить вручную и тогда они будут доступны на клиенте. +Функция ПараметрыЗапуска() Экспорт + + Параметры = Новый Структура; + + Параметры.Вставить("ВыполнятьМодульноеТестирование", Ложь); + + Параметры.Вставить("reportPath", ""); + Параметры.Вставить("closeAfterTests", Истина); + Параметры.Вставить("filter", ПараметрыФильтрации()); + Параметры.Вставить("settings", НастройкиВыполнения()); + Параметры.Вставить("reportFormat", "jUnit"); + Параметры.Вставить("showReport", Ложь); + Параметры.Вставить("logging", ПараметрыЛогирования()); + Параметры.Вставить("exitCode", ""); + + Параметры.Вставить("ПодключатьВнешниеКомпоненты", Истина); + + Возврат Параметры; + +КонецФункции + +// Выражение предиката. +// +// Параметры: +// ВидСравнения - Строка - см. ЮТПредикаты.Выражения +// ИмяРеквизита - Строка - Имя реквизита +// Значение - Произвольный - Значение +// +// Возвращаемое значение: +// Структура - Выражение предиката: +// * ИмяРеквизита - Неопределено, Строка - Имя проверяемого реквизита +// * ВидСравнения - Строка +// * Значение - Произвольный, Неопределено - Операнд выражения +Функция ВыражениеПредиката(ВидСравнения, ИмяРеквизита = Неопределено, Значение = Неопределено) Экспорт + + Выражение = Новый Структура(); + ЮТОбщий.УказатьТипСтруктуры(Выражение, "Предикат"); + + Выражение.Вставить("ИмяРеквизита", ИмяРеквизита); + Выражение.Вставить("ВидСравнения", ВидСравнения); + Выражение.Вставить("Значение", Значение); + + Возврат Выражение; + +КонецФункции + +// Доступные параметры (настройки) исполнения тестов +// +// Возвращаемое значение: +// ФиксированнаяСтруктура - Параметры исполнения теста: +// * ВТранзакции - Строка - Тест должен выполняться в транзакции +// * УдалениеТестовыхДанных - Строка - Тест должен удалить созданные тестовые данные +// * Перед - Строка - Перед тестом должен выполниться указанный обработчик события вместо основного +// * После - Строка - После теста должен выполниться указанный обработчик события вместо основного +Функция ПараметрыИсполненияТеста() Экспорт + + Параметры = Новый Структура(); + Параметры.Вставить("ВТранзакции", "ВТранзакции"); + Параметры.Вставить("УдалениеТестовыхДанных", "УдалениеТестовыхДанных"); + Параметры.Вставить("Перед", "Перед"); + Параметры.Вставить("После", "После"); + + Возврат Новый ФиксированнаяСтруктура(Параметры); + +КонецФункции + +// Параметры создания объектов, используется при загрузке макетов. +// +// Параметры: +// ПараметрыЗаписи - см. ЮТОбщий.ПараметрыЗаписи +// ФикцияОбязательныхПолей - Булево - Фикция обязательных полей +// +// Возвращаемое значение: +// Структура - Параметры создания объектов: +// * ФикцияОбязательныхПолей - Булево +// * ПараметрыЗаписи - см. ЮТОбщий.ПараметрыЗаписи +Функция ПараметрыСозданияОбъектов(Знач ПараметрыЗаписи = Неопределено, ФикцияОбязательныхПолей = Ложь) Экспорт + + Если ПараметрыЗаписи = Неопределено Тогда + ПараметрыЗаписи = ЮТОбщий.ПараметрыЗаписи(); + Иначе + ВходныеПараметрыЗаписи = ПараметрыЗаписи; + ПараметрыЗаписи = ЮТОбщий.ПараметрыЗаписи(); + ЗаполнитьЗначенияСвойств(ПараметрыЗаписи, ВходныеПараметрыЗаписи); + КонецЕсли; + + Возврат Новый Структура("ФикцияОбязательныхПолей, ПараметрыЗаписи", ФикцияОбязательныхПолей, ПараметрыЗаписи); + +КонецФункции + +#КонецОбласти + +#Область СлужебныеПроцедурыИФункции + +// ПараметрыФильтрации +// Возвращает структуру отборов для поиска тестов +// Возвращаемое значение: +// Структура - Параметры фильтрации: +// * extensions - Неопределено - Нет фильтрации по расширениям +// - Массив из Строка - Список тестовых расширений +// * modules - Неопределено - Нет фильтрации по модулям +// - Массив из Строка - Список тестовых модулей +// * suites - Неопределено - Нет фильтрации по тестовым наборам +// - Массив из Строка - Список тестовых наборов +// * paths - Неопределено - Нет фильтрации по путям +// - Массив из Строка - Список путей до тестовых методов, путь может быть не полным. +// Например: +// + tests - Ищем тесты в расширении tests +// + tests.ОМ_ОбщегоНазначения - Ищем тесты в модуле ОМ_ОбщегоНазначения расширения tests +// + tests.ОМ_ОбщегоНазначения.ПолучитьЗначениеРеквизита - указание конкретного теста +// * tags - Неопределено - Нет фильтрации по тегам +// - Массив из Строка - Список тэгов +// * contexts - Неопределено - Нет фильтрации по контекстам +// - Массив из Строка - Список тестируемых контекстов +// * tests - Неопределено - Нет фильтрации по тестам +// - Массив из Строка - Список полных имен тестовых методов. ИмяМодуля.ИмяМетода{.Контекст} +Функция ПараметрыФильтрации() Экспорт + + Параметры = Новый Структура; + Параметры.Вставить("extensions", Неопределено); + Параметры.Вставить("modules", Неопределено); + Параметры.Вставить("suites", Неопределено); + Параметры.Вставить("tags", Неопределено); + Параметры.Вставить("contexts", Неопределено); + Параметры.Вставить("paths", Неопределено); + Параметры.Вставить("tests", Неопределено); + + Возврат Параметры; + +КонецФункции + +Функция НастройкиВыполнения() Экспорт + + Настройки = Новый Структура(); + + ПараметрыИсполнения = ПараметрыИсполненияТеста(); + Настройки.Вставить(ПараметрыИсполнения.ВТранзакции, Ложь); + + Возврат Настройки; + +КонецФункции + +Функция ПараметрыЛогирования() Экспорт + + Параметры = Новый Структура(); + Параметры.Вставить("file", ""); + Параметры.Вставить("console", Ложь); + Параметры.Вставить("enable", Неопределено); + Параметры.Вставить("level", ЮТЛогирование.УровниЛога().Отладка); + + Возврат Параметры; + +КонецФункции + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТФабрикаСлужебный.xml b/src/cfe/YAXUnit/CommonModules/ЮТФабрикаСлужебный.xml new file mode 100644 index 0000000..6a7e4dd --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТФабрикаСлужебный.xml @@ -0,0 +1,23 @@ + + + + + ЮТФабрикаСлужебный + + + ru + Фабрика + + + + false + true + true + false + true + false + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТФабрикаСлужебный/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТФабрикаСлужебный/Ext/Module.bsl new file mode 100644 index 0000000..c088c35 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТФабрикаСлужебный/Ext/Module.bsl @@ -0,0 +1,684 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область СлужебныйПрограммныйИнтерфейс + +#Область Перечисления + +// Типы ошибок. +// +// Возвращаемое значение: +// ФиксированнаяСтруктура - Типы возможных ошибок: +// * ТестНеРеализован - Строка +// * ОшибкаСравнения - Строка +// * ОшибкаОбработкиСобытия - Строка +// * Утверждений - Строка +// * Исполнения - Строка +// * ЧтенияТестов - Строка +// * МалоПараметров - Строка +// * МногоПараметров - Строка +// * НекорректныйКонтекстИсполнения - Строка +// * Пропущен - Строка +Функция ТипыОшибок() Экспорт + + Типы = Новый Структура; + + Для Каждого ТипОшибки Из ПараметрыТиповОшибок() Цикл + Типы.Вставить(ТипОшибки.Ключ, ТипОшибки.Ключ); + КонецЦикла; + + //@skip-check constructor-function-return-section + Возврат Новый ФиксированнаяСтруктура(Типы); + +КонецФункции + +Функция ПараметрыТиповОшибок(Кешировать = Истина) Экспорт + + Если Кешировать Тогда + ЮТСлужебныйПовторногоИспользования.ПараметрыТиповОшибок(); + КонецЕсли; + + Статусы = ЮТФабрика.СтатусыИсполненияТеста(); + Реквизиты = "Ключ, Представление, Статус"; + + ТипыОшибок = Новый Массив(); + ТипыОшибок.Добавить(Новый Структура(Реквизиты, "ТестНеРеализован", "Не реализован", Статусы.НеРеализован)); + ТипыОшибок.Добавить(Новый Структура(Реквизиты, "ОшибкаСравнения", "Ошибка сравнения", Статусы.Ошибка)); + ТипыОшибок.Добавить(Новый Структура(Реквизиты, "ОшибкаОбработкиСобытия", "Ошибка обработки события", Статусы.Сломан)); + ТипыОшибок.Добавить(Новый Структура(Реквизиты, "Утверждений", "Ошибка утверждений", Статусы.Ошибка)); + ТипыОшибок.Добавить(Новый Структура(Реквизиты, "Исполнения", "Ошибка исполнения", Статусы.Сломан)); + ТипыОшибок.Добавить(Новый Структура(Реквизиты, "ЧтенияТестов", "Загрузки тестов", Статусы.Сломан)); + ТипыОшибок.Добавить(Новый Структура(Реквизиты, "МалоПараметров", "Мало фактических параметров", Статусы.Сломан)); + ТипыОшибок.Добавить(Новый Структура(Реквизиты, "МногоПараметров", "Много фактических параметров", Статусы.Сломан)); + ТипыОшибок.Добавить(Новый Структура(Реквизиты, "НекорректныйКонтекстИсполнения", "Некорректный контекст исполнения", Статусы.Пропущен)); + ТипыОшибок.Добавить(Новый Структура(Реквизиты, "Пропущен", "Пропущен", Статусы.Пропущен)); + + Возврат ЮТКоллекции.ВСтруктуру(ТипыОшибок, "Ключ"); + +КонецФункции + +#КонецОбласти + +#Область СтруктурыДанных + +// Описание тестового модуля. +// +// Параметры: +// МетаданныеМодуля - см. ЮТФабрикаСлужебный.ОписаниеМодуля +// НаборыТестов - Массив из см. ЮТФабрикаСлужебный.ОписаниеТестовогоНабора +// +// Возвращаемое значение: +// Структура - Описание тестового модуля: +// * МетаданныеМодуля - см. ЮТФабрикаСлужебный.ОписаниеМодуля +// * НаборыТестов - Массив из см. ЮТФабрикаСлужебный.ОписаниеТестовогоНабора +// * Ошибки - Массив из см. ЮТФабрикаСлужебный.ОписаниеВозникшейОшибки +// * НастройкиВыполнения- Структура - Настройки исполнения теста +Функция ОписаниеТестовогоМодуля(МетаданныеМодуля, НаборыТестов) Экспорт + + Описание = Новый Структура; + Описание.Вставить("МетаданныеМодуля", МетаданныеМодуля); + Описание.Вставить("НаборыТестов", НаборыТестов); + Описание.Вставить("Ошибки", Новый Массив); + Описание.Вставить("НастройкиВыполнения", Новый Структура()); + + Возврат Описание; + +КонецФункции + +// ОписаниеТестовогоНабора +// Возвращает описание регистрируемого тестового набора. +// Эта структура используется на этапе формирования описаний имеющихся тестов +// Параметры: +// Имя - Строка - Имя набора +// ТегиСтрокой - Строка - Теги набора +// +// Возвращаемое значение: +// Структура - Описание тестового набора: +// * Имя - Строка - Имя набора +// * Представление - Строка - Представление, краткое описание +// * Теги - Массив из Строка - Коллекция тегов набора +// * Тесты - Массив из см. ОписаниеТеста - Коллекция тестов набора, см. ОписаниеТеста +// * Ошибки - Массив из см. ЮТФабрикаСлужебный.ОписаниеВозникшейОшибки - Описания ошибок регистрации тестов +// * НастройкиВыполнения- Структура - Настройки исполнения теста +Функция ОписаниеТестовогоНабора(Имя, ТегиСтрокой = "") Экспорт + + Описание = Новый Структура; + Описание.Вставить("Имя", Строка(Имя)); + Описание.Вставить("Представление", Строка(Имя)); + Описание.Вставить("Теги", СтрРазделить(ТегиСтрокой, ", ", Ложь)); + Описание.Вставить("Тесты", Новый Массив); + Описание.Вставить("Ошибки", Новый Массив); + Описание.Вставить("НастройкиВыполнения", Новый Структура()); + + Возврат Описание; + +КонецФункции + +// ОписаниеТеста +// Возвращает описание регистрируемого теста. +// Эта структура используется на этапе формирования описаний имеющихся тестов +// Параметры: +// Имя - Строка - Имя тестового метода +// Представление - Строка - Представление, краткое описание теста +// КонтекстыВызова - Массив из Строка - Контексты исполнения теста, см. ЮТФабрика.КонтекстыВызова +// ТегиСтрокой - Строка - Теги теста +// +// Возвращаемое значение: +// Структура - Описание теста: +// * Имя - Строка - Имя теста (тестового метода) +// * Представление - Строка - Представление теста +// * Теги - Массив из Строка - Теги теста +// * КонтекстВызова - Массив из Строка - Контексты исполнения теста +// * НастройкиВыполнения- Структура - Настройки исполнения теста +// * Параметры - Неопределено, Массив из Произвольный - Параметры теста +// * НомерВНаборе - Число - Порядковый номер теста в наборе +Функция ОписаниеТеста(Имя, Представление, КонтекстыВызова, Знач ТегиСтрокой = "") Экспорт + + Если ТегиСтрокой = Неопределено Тогда + ТегиСтрокой = ""; + КонецЕсли; + + Описание = Новый Структура(); + Описание.Вставить("Имя", Строка(Имя)); + Описание.Вставить("Представление", Строка(Представление)); + Описание.Вставить("Теги", СтрРазделить(ТегиСтрокой, ", ", Ложь)); + Описание.Вставить("КонтекстВызова", КонтекстыВызова); + Описание.Вставить("НастройкиВыполнения", Новый Структура()); + Описание.Вставить("Параметры", Неопределено); + Описание.Вставить("НомерВНаборе", 0); + + Возврат Описание; + +КонецФункции + +// Описание исполняемого тестового модуля. +// Содержит всю необходимую информацию для прогона тестов, а также данные результата +// Параметры: +// ТестовыйМодуль - см. ОписаниеТестовогоМодуля +// +// Возвращаемое значение: +// Структура - Описание тестового модуля: +// * МетаданныеМодуля - см. ЮТФабрикаСлужебный.ОписаниеМодуля +// * НаборыТестов - Массив из см. ЮТФабрикаСлужебный.ОписаниеИсполняемогоНабораТестов +// * Ошибки - Массив из см. ЮТФабрикаСлужебный.ОписаниеВозникшейОшибки +// * НастройкиВыполнения- Структура - Настройки исполнения теста +Функция ОписаниеИсполняемогоТестовогоМодуля(ТестовыйМодуль) Экспорт + + Описание = Новый Структура; + + Описание.Вставить("МетаданныеМодуля", ТестовыйМодуль.МетаданныеМодуля); + Описание.Вставить("НаборыТестов", Новый Массив); + Описание.Вставить("Ошибки", ЮТКоллекции.СкопироватьМассив(ТестовыйМодуль.Ошибки)); + Описание.Вставить("НастройкиВыполнения", ЮТКоллекции.СкопироватьСтруктуру(ТестовыйМодуль.НастройкиВыполнения)); + + Возврат Описание; + +КонецФункции + +// ОписаниеИсполняемогоНабораТестов +// Возвращает описание исполняемого тестового набора. +// Содержит данные необходимые для выполнения прогона тестов +// Параметры: +// НаборТестов - См. ОписаниеТестовогоНабора +// ТестовыйМодуль - См. ОписаниеТестовогоМодуля +// +// Возвращаемое значение: +// Структура - Описание исполняемого набора тестов: +// * Имя - Строка - Имя набора +// * Представление - Строка - Представление набора +// * Теги - Массив из Строка - Тэги набора +// * Ошибки - Массив из см. ЮТФабрикаСлужебный.ОписаниеВозникшейОшибки - Описания ошибок выполнения теста +// * Режим - Строка - Режим исполнения набора, см. ЮТФабрика.КонтекстыВызова +// * МетаданныеМодуля - см. ЮТФабрикаСлужебный.ОписаниеМодуля +// * Тесты - Массив из см. ОписаниеИсполняемогоТеста - Тесты набора, структуру тестов см. ОписаниеИсполняемогоТеста +// * Выполнять - Булево - Признак, что можно выполнить прогон набора (нет ошибок блокирующих запуск) +// * ДатаСтарта - Число - Дата запуска набора +// * Длительность - Число - Продолжительность выполнения набора +// * НастройкиВыполнения - Структура - Настройки исполнения теста +// * ТестовыйМодуль - См. ОписаниеТестовогоМодуля +Функция ОписаниеИсполняемогоНабораТестов(НаборТестов, ТестовыйМодуль) Экспорт + + Описание = Новый Структура(); + + Описание.Вставить("Имя", НаборТестов.Имя); + Описание.Вставить("Представление", НаборТестов.Представление); + Описание.Вставить("Теги", НаборТестов.Теги); + Описание.Вставить("Ошибки", ЮТКоллекции.СкопироватьМассив(НаборТестов.Ошибки)); + Описание.Вставить("Режим", ""); + Описание.Вставить("ТестовыйМодуль", ТестовыйМодуль); + Описание.Вставить("МетаданныеМодуля", ТестовыйМодуль.МетаданныеМодуля); + Описание.Вставить("Тесты", Новый Массив); + Описание.Вставить("Выполнять", Описание.Ошибки.Количество() = 0); + Описание.Вставить("ДатаСтарта", 0); + Описание.Вставить("Длительность", 0); + Описание.Вставить("НастройкиВыполнения", НаборТестов.НастройкиВыполнения); + + Возврат Описание; + +КонецФункции + +// ОписаниеИсполняемогоТеста +// Возвращает описание исполняемого теста +// Содержит данные необходимые для выполнения прогона тестов +// +// Параметры: +// Тест - См. ОписаниеТеста +// Режим - См. ЮТФабрика.КонтекстыВызова +// ТестовыйМодуль - См. ОписаниеТестовогоМодуля +// +// Возвращаемое значение: +// Структура - Описание исполняемого теста: +// * Имя - Строка - Имя/представление теста +// * Метод - Строка - Имя тестового метода +// * ПолноеИмяМетода - Строка - Полное имя тестового метода, ИмяМодуля.ИмяМетода +// * Теги - Массив из Строка - Теги теста +// * Режим - Строка - Режим исполнения теста, см. ЮТФабрика.КонтекстыВызова +// * ДатаСтарта - Число - Дата запуска теста +// * Длительность - Число - Продолжительность выполнения теста +// * Статус - Строка - Статус выполнения теста, см. ЮТФабрика.СтатусыИсполненияТеста +// * Ошибки - Массив из см. ЮТФабрикаСлужебный.ОписаниеВозникшейОшибки - Описания ошибок выполнения теста, см. ЮТФабрикаСлужебный.ОписаниеВозникшейОшибки +// * НастройкиВыполнения- Структура - Настройки исполнения теста +// * Параметры - Неопределено, Массив из Произвольный - Набор параметров теста +// * НомерВНаборе - Число - Порядковый номер теста в наборе +Функция ОписаниеИсполняемогоТеста(Тест, Режим, ТестовыйМодуль) Экспорт + + ПолноеИмяМетода = СтрШаблон("%1.%2", ТестовыйМодуль.МетаданныеМодуля.Имя, Тест.Имя); + Представление = ПредставлениеТеста(Тест); + + ОписаниеТеста = Новый Структура; + ОписаниеТеста.Вставить("Имя", Представление); + ОписаниеТеста.Вставить("Метод", Тест.Имя); + ОписаниеТеста.Вставить("ПолноеИмяМетода", ПолноеИмяМетода); + ОписаниеТеста.Вставить("Теги", Тест.Теги); + ОписаниеТеста.Вставить("Режим", Режим); + ОписаниеТеста.Вставить("ДатаСтарта", 0); + ОписаниеТеста.Вставить("Длительность", 0); + ОписаниеТеста.Вставить("Статус", ЮТФабрика.СтатусыИсполненияТеста().Ожидание); + ОписаниеТеста.Вставить("Ошибки", Новый Массив); + ОписаниеТеста.Вставить("НастройкиВыполнения", Тест.НастройкиВыполнения); + ОписаниеТеста.Вставить("Параметры", Тест.Параметры); + ОписаниеТеста.Вставить("НомерВНаборе", Тест.НомерВНаборе); + + //@skip-check constructor-function-return-section + Возврат ОписаниеТеста; + +КонецФункции + +// ОписаниеМодуля +// Возвращает структуру описания модуля +// Возвращаемое значение: +// Структура - Описание модуля: +// * Имя - Строка - Имя модуля +// * ПолноеИмя - Строка - Полное имя модуля +// * Расширение - Строка - Имя расширения, владельца модуля +// * КлиентУправляемоеПриложение - Булево - Доступность контекста +// * КлиентОбычноеПриложение - Булево - Доступность контекста +// * Сервер - Булево - Доступность контекста +// * ВызовСервера - Булево - Доступность контекста +// * Глобальный - Булево - Доступность контекста +Функция ОписаниеМодуля() Экспорт + + Описание = Новый Структура; + Описание.Вставить("Имя", ""); + Описание.Вставить("ПолноеИмя", ""); + Описание.Вставить("Расширение", ""); + Описание.Вставить("КлиентУправляемоеПриложение", Ложь); + Описание.Вставить("КлиентОбычноеПриложение", Ложь); + Описание.Вставить("Сервер", Ложь); + Описание.Вставить("ВызовСервера", Ложь); + Описание.Вставить("Глобальный", Ложь); + + Возврат Описание; + +КонецФункции + +// ОписаниеВозникшейОшибки +// Возвращает базовую структуру ошибки +// +// Параметры: +// Сообщение - Строка - Описание ошибки +// +// Возвращаемое значение: +// Структура - Описание возникшей ошибки: +// * Сообщение - Строка - Описание возникшей ошибки +// * Стек - Строка - Стек возникшей ошибки +// * ТипОшибки - Строка - Тип возникшей ошибки. Доступные значения см. ЮТФабрикаСлужебный.ТипыОшибок +// * Лог - Массив из Строка +Функция ОписаниеВозникшейОшибки(Сообщение) Экспорт + + Описание = Новый Структура("Стек, ТипОшибки", "", ""); + Описание.Вставить("Сообщение", Сообщение); + Описание.Вставить("Лог", Новый Массив); + + Возврат Описание; + +КонецФункции + +// Возвращает базовую структуру ошибки проверки факта и ожидания +// +// Параметры: +// Сообщение - Строка +// +// Возвращаемое значение: +// Структура - Описание возникшей ошибки: +// * Сообщение - Строка - Описание возникшей ошибки +// * Стек - Строка - Стек возникшей ошибки +// * ТипОшибки - Строка - Тип возникшей ошибки. Доступные значения см. ЮТФабрикаСлужебный.ТипыОшибок +// * ПроверяемоеЗначение - Произвольный - Проверяемое, фактическое значение +// * ОжидаемоеЗначение - Произвольный - Ожидаемое значение +Функция ОписаниеОшибкиСравнения(Сообщение) Экспорт + + Описание = ОписаниеВозникшейОшибки(Сообщение); + Описание.ТипОшибки = ТипыОшибок().Утверждений; + Описание.Вставить("ПроверяемоеЗначение"); + Описание.Вставить("ОжидаемоеЗначение"); + + //@skip-check constructor-function-return-section + Возврат Описание; + +КонецФункции + +// Возвращает базовую структуру ошибки пропуска теста +// +// Параметры: +// Сообщение - Строка +// +// Возвращаемое значение: +// Структура - Описание возникшей ошибки: +// * Сообщение - Строка - Описание возникшей ошибки +// * Стек - Строка - Стек возникшей ошибки +// * ТипОшибки - Строка - Тип возникшей ошибки. Доступные значения +// См. ЮТФабрикаСлужебный.ТипыОшибок +Функция ОписаниеОшибкиПропуска(Сообщение) Экспорт + + Описание = ОписаниеВозникшейОшибки(Сообщение); + Описание.ТипОшибки = ТипыОшибок().Пропущен; + + Возврат Описание; + +КонецФункции + +// Описание события исполнения тестов. +// +// Параметры: +// Модуль - см. ЮТФабрикаСлужебный.ОписаниеТестовогоМодуля +// Набор - см. ЮТФабрикаСлужебный.ОписаниеИсполняемогоНабораТестов +// Тест - см. ЮТФабрикаСлужебный.ОписаниеИсполняемогоТеста +// +// Возвращаемое значение: +// Структура - Описание события исполнения тестов: +// * Модуль - см. ЮТФабрикаСлужебный.ОписаниеТестовогоМодуля +// * Набор - см. ЮТФабрикаСлужебный.ОписаниеИсполняемогоНабораТестов +// * Тест - см. ЮТФабрикаСлужебный.ОписаниеИсполняемогоТеста +Функция ОписаниеСобытияИсполненияТестов(Модуль, Набор = Неопределено, Тест = Неопределено) Экспорт + + Описание = Новый Структура(); + Описание.Вставить("Модуль", Модуль); + Описание.Вставить("Набор", Набор); + Описание.Вставить("Тест", Тест); + + //@skip-check constructor-function-return-section + Возврат Описание; + +КонецФункции + +// Описание категория набора тестов. +// +// Параметры: +// ТестовыйМодуль - см. ЮТФабрикаСлужебный.ОписаниеТестовогоМодуля +// +// Возвращаемое значение: +// Структура - Описание категория набора тестов: +// * ТестовыйМодуль - см. ЮТФабрикаСлужебный.ОписаниеТестовогоМодуля +// * Клиентские - Массив из см. ЮТФабрикаСлужебный.ОписаниеИсполняемогоНабораТестов +// * Серверные - Массив из см. ЮТФабрикаСлужебный.ОписаниеИсполняемогоНабораТестов +// * Пропущенные - Массив из см. ЮТФабрикаСлужебный.ОписаниеИсполняемогоНабораТестов +Функция ОписаниеКатегорияНабораТестов(ТестовыйМодуль) Экспорт + + КатегорииНаборов = Новый Структура(); + КатегорииНаборов.Вставить("ТестовыйМодуль", ТестовыйМодуль); + КатегорииНаборов.Вставить("Клиентские", Новый Массив()); + КатегорииНаборов.Вставить("Серверные", Новый Массив()); + КатегорииНаборов.Вставить("Пропущенные", Новый Массив()); + + //@skip-check constructor-function-return-section + Возврат КатегорииНаборов; + +КонецФункции + +// Формирует описание проверяемого значения. +// Используется в утверждения для формирования дружелюбного сообщения об ошибке. +// +// Параметры: +// ПроверяемоеЗначение - Произвольный - Проверяемое значение +// +// Возвращаемое значение: +// Структура - Описание проверяемого значения: +// * Значение - Произвольный +// * Представление - Строка - Представление объекта +// - Неопределено - Если не указано тогда используется платформенное предсталение (`Строка(Значение)`) +// * ИмяСвойства - Строка, Число, Неопределено - Имя проверяемого реквизита, индекса +Функция ОписаниеПроверяемогоЗначения(ПроверяемоеЗначение) Экспорт + + Описание = Новый Структура(); + Описание.Вставить("Значение", ПроверяемоеЗначение); + Описание.Вставить("Представление", Неопределено); + Описание.Вставить("ИмяСвойства", Неопределено); + + Возврат Описание; + +КонецФункции + +// Описание проверки. +// +// Параметры: +// ПроверяемоеЗначение - Произвольный +// +// Возвращаемое значение: +// Структура - Описание проверки: +// * ОбъектПроверки - см. ОписаниеПроверяемогоЗначения +// * ПрефиксОшибки - Строка, Неопределено - +// * ОписаниеПроверки - Строка, Неопределено - +Функция ОписаниеПроверки(ПроверяемоеЗначение) Экспорт + + Описание = Новый Структура(); + Описание.Вставить("ОбъектПроверки", ОписаниеПроверяемогоЗначения(ПроверяемоеЗначение)); + Описание.Вставить("ПрефиксОшибки", Неопределено); + Описание.Вставить("ОписаниеПроверки", Неопределено); + + Возврат Описание; + +КонецФункции + +#КонецОбласти + +#Область КонструкторыКонтекстов + +// Данные контекста исполнения. +// +// Возвращаемое значение: +// Структура - Данные контекста исполнения: +// * Уровень - Строка - Возможные значения см. ЮТФабрика.УровниИсполнения +// * Модуль - Неопределено - Нет исполняемого модуля +// - см. ОписаниеТестовогоМодуля +// * Набор - Неопределено - Нет исполняемого тестового набора +// - см. ОписаниеИсполняемогоНабораТестов +// * Тест - Неопределено - Нет исполняемого теста +// - см. ОписаниеИсполняемогоТеста +Функция НовыйКонтекстИсполнения() Экспорт + + Контекст = Новый Структура(); + Контекст.Вставить("Уровень", ""); + Контекст.Вставить("Модуль", Неопределено); + Контекст.Вставить("Набор", Неопределено); + Контекст.Вставить("Тест", Неопределено); + + Возврат Контекст; + +КонецФункции + +// Описание результата проверки. +// +// Параметры: +// Успешно - Булево - Успешно +// +// Возвращаемое значение: +// Структура - Описание результата проверки: +// * Сообщения - Массив из Произвольный +// * Успешно - Булево +Функция ОписаниеРезультатаПроверки(Успешно = Истина) Экспорт + + Описание = Новый Структура(); + Описание.Вставить("Сообщения", Новый Массив); + Описание.Вставить("Успешно", Истина); + + Возврат Описание; + +КонецФункции + +#КонецОбласти + +// КонтекстыМодуля +// Возвращает коллекцию доступных контекстов выполнения модуля +// Параметры: +// Модуль - См. ОписаниеМодуля +// +// Возвращаемое значение: +// Массив из Строка - Контексты модуля, возможные значения см. ЮТФабрика.КонтекстыВызова +Функция КонтекстыМодуля(Модуль) Экспорт + + Контексты = ЮТФабрика.КонтекстыВызова(); + + КонтекстыМодуля = Новый Массив(); + + Если Модуль.Сервер Тогда + КонтекстыМодуля.Добавить(Контексты.Сервер); + КонецЕсли; + + Если Модуль.КлиентУправляемоеПриложение Тогда + КонтекстыМодуля.Добавить(Контексты.КлиентУправляемоеПриложение); + КонецЕсли; + + Если Модуль.КлиентОбычноеПриложение Тогда + КонтекстыМодуля.Добавить(Контексты.КлиентОбычноеПриложение); + КонецЕсли; + + Возврат КонтекстыМодуля; + +КонецФункции + +// КонтекстыПриложения +// Возвращает коллекцию доступных контекстов приложения +// Возвращаемое значение: +// Массив из Строка - Контексты приложения, возможные значения см. ЮТФабрика.КонтекстыВызова +Функция КонтекстыПриложения() Экспорт + +#Если НЕ Клиент Тогда + ВызватьИсключение "Метод получения контекстов приложения должен вызываться с клиента"; +#КонецЕсли + + Контексты = ЮТФабрика.КонтекстыВызова(); + КонтекстыПриложения = Новый Массив(); + + КонтекстыПриложения.Добавить(Контексты.Сервер); + КонтекстыПриложения.Добавить(Контексты.ВызовСервера); + +#Если ТолстыйКлиентОбычноеПриложение Тогда + КонтекстыПриложения.Добавить(Контексты.КлиентОбычноеПриложение); +#ИначеЕсли ТолстыйКлиентУправляемоеПриложение Или ТонкийКлиент Тогда + КонтекстыПриложения.Добавить(Контексты.КлиентУправляемоеПриложение); +#КонецЕсли + + Возврат КонтекстыПриложения; + +КонецФункции + +// КонтекстИсполнения +// Возвращает контекст исполнения по контексту вызова +// Параметры: +// КонтекстВызова - Строка - Контекст вызова, см. ЮТФабрика.КонтекстыВызова +// +// Возвращаемое значение: +// Неопределено, Строка - Контекст исполнения +Функция КонтекстИсполнения(КонтекстВызова) Экспорт + + КонтекстыВызова = ЮТФабрика.КонтекстыВызова(); + + Если КонтекстВызова = КонтекстыВызова.Сервер Тогда + + Возврат ЮТФабрика.КонтекстыИсполнения().Сервер; + + ИначеЕсли КонтекстВызова = КонтекстыВызова.КлиентУправляемоеПриложение + ИЛИ КонтекстВызова = КонтекстыВызова.КлиентОбычноеПриложение + ИЛИ КонтекстВызова = КонтекстыВызова.ВызовСервера Тогда + + Возврат ЮТФабрика.КонтекстыИсполнения().Клиент; + + Иначе + + Возврат Неопределено; + + КонецЕсли; + +КонецФункции + +// Формирует представление теста +// +// Параметры: +// Тест - см. ОписаниеТеста +// +// Возвращаемое значение: +// Строка - Представление теста +Функция ПредставлениеТеста(Тест) Экспорт + + Если ЗначениеЗаполнено(Тест.Представление) Тогда + Представление = Тест.Представление; + ИначеЕсли ЗначениеЗаполнено(Тест.Параметры) Тогда + ПредставлениеПараметров = СтрСоединить(Тест.Параметры, ", "); + Представление = СтрШаблон("%1(%2)", Тест.Имя, ПредставлениеПараметров); + Иначе + Представление = Тест.Имя; + КонецЕсли; + + Возврат Представление; + +КонецФункции + +Функция ПараметрыЗаполненияТаблицыЗначений(Знач ПараметрыСозданияОбъектов = Неопределено) Экспорт + + Если ПараметрыСозданияОбъектов = Неопределено Тогда + ПараметрыСозданияОбъектов = ЮТФабрика.ПараметрыСозданияОбъектов(); + Иначе + ВходныеПараметрыСозданияОбъектов = ПараметрыСозданияОбъектов; + ПараметрыСозданияОбъектов = ЮТФабрика.ПараметрыСозданияОбъектов(); + ЗаполнитьЗначенияСвойств(ПараметрыСозданияОбъектов, ВходныеПараметрыСозданияОбъектов); + КонецЕсли; + + Возврат Новый ФиксированнаяСтруктура("СозданиеОбъектовМетаданных", ПараметрыСозданияОбъектов); + +КонецФункции + +// Параметры генератора отчета. +// Описывает предоставляемые модулем форматы отчетов +// +// Возвращаемое значение: +// Структура - Параметры генератора отчета: +// * Форматы - Структура - Форматы отчетов, предоставляемые модулем +Функция ПараметрыГенератораОтчета() Экспорт + + Параметры = Новый Структура(); + Параметры.Вставить("Форматы", Новый Структура); + + Возврат Параметры; + +КонецФункции + +// Описание формата отчета. +// +// Параметры: +// Идентификатор - Строка - Уникальный идентификатор формата отчета +// Представление - Строка - Пользовательское представление отчета, выводится в форму настроек тестирования +// +// Возвращаемое значение: +// Структура - Описание формата отчета: +// * Идентификатор - Строка - Уникальный идентификатор формата отчета +// * Представление - Строка - Пользовательское представление отчета, выводится в форму настроек тестирования +// * ЗаписьВКаталог - Булево - Отчет записывается в каталог, в этом случае должен быть установлен призак `СамостоятельнаяЗаписьОтчета` +// * ФильтрВыбораФайла - Строка - Фильтр выбора, используется в форме настроек тестирования +// * ИмяФайлаПоУмолчанию - Строка - Для отчетов, записываемых в файл, имя файла если в параметрах указан каталог +// * СамостоятельнаяЗаписьОтчета - Булево - Способ записи отчета в файлы. +// Истина - Модуль формирования отчета самостоятельно записывает отчет +// Ложь - Модуль формирования отчета генерирует данные, которые записываются движком +Функция ОписаниеФорматаОтчета(Идентификатор, Представление) Экспорт + + Описание = Новый Структура(); + Описание.Вставить("Идентификатор", Идентификатор); + Описание.Вставить("Представление", Представление); + Описание.Вставить("ЗаписьВКаталог", Ложь); + Описание.Вставить("ФильтрВыбораФайла", ""); + Описание.Вставить("ИмяФайлаПоУмолчанию", ""); + Описание.Вставить("СамостоятельнаяЗаписьОтчета", Ложь); + + Возврат Описание; + +КонецФункции +#КонецОбласти + +#Область СлужебныеПроцедурыИФункции + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТФайлы.xml b/src/cfe/YAXUnit/CommonModules/ЮТФайлы.xml new file mode 100644 index 0000000..01e9009 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТФайлы.xml @@ -0,0 +1,23 @@ + + + + + ЮТФайлы + + + ru + Файлы + + + + false + true + true + false + true + false + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТФайлы/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТФайлы/Ext/Module.bsl new file mode 100644 index 0000000..a17b5ae --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТФайлы/Ext/Module.bsl @@ -0,0 +1,201 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +/////////////////////////////////////////////////////////////////// +// Содержит методы по работе с файлами +/////////////////////////////////////////////////////////////////// +#Область ПрограммныйИнтерфейс + +// Проверяет существование файла +// +// Параметры: +// ПутьКФайлу - Строка +// Обработчик - ОписаниеОповещения - Обработчик асинхронного получения свойства файла. Если обработчик указан, но проверка выполняется асинхронно. +// - Неопределено - Проверка выполняется синхронно. +// +// Возвращаемое значение: +// Булево - Существует +Функция Существует(ПутьКФайлу, Обработчик = Неопределено) Экспорт + + Файл = Новый Файл(ПутьКФайлу); + +#Если Клиент Тогда + Если Обработчик = Неопределено Тогда + Возврат Файл.Существует(); + Иначе + Файл.НачатьПроверкуСуществования(Обработчик); + КонецЕсли; +#Иначе + Возврат Файл.Существует(); +#КонецЕсли + +КонецФункции + +// Проверяет, что по указанному пути находится каталог +// +// Параметры: +// ПутьКФайлу - Строка +// Обработчик - ОписаниеОповещения - Обработчик асинхронного получения свойства файла. Если обработчик указан, но проверка выполняется асинхронно. +// - Неопределено - Проверка выполняется синхронно. +// +// Возвращаемое значение: +// Булево - Это каталог +Функция ЭтоКаталог(ПутьКФайлу, Обработчик = Неопределено) Экспорт + + Файл = Новый Файл(ПутьКФайлу); + +#Если Клиент Тогда + Если Обработчик <> Неопределено Тогда + ОбработчикПолученияАтрибута = ОбработчикПолученияАтрибута(Файл, "ЭтоКаталог", Обработчик, Ложь); + Файл.НачатьПроверкуСуществования(ОбработчикПолученияАтрибута); + + Возврат Неопределено; + КонецЕсли; +#КонецЕсли + + Возврат Файл.Существует() И Файл.ЭтоКаталог(); + +КонецФункции + +// Возвращает путь к вложенному элементу +// +// Параметры: +// Путь1 - Строка - базовый путь к каталогу +// Путь2 - Строка - относительный путь к вложенному элементу +// Путь3 - Строка - относительный путь к вложенному элементу +// Путь4 - Строка - относительный путь к вложенному элементу +// Путь5 - Строка - относительный путь к вложенному элементу +// +// Возвращаемое значение: +// Строка - Объединенный путь +Функция ОбъединитьПути(Путь1, Путь2, Путь3 = Неопределено, Путь4 = Неопределено, Путь5 = Неопределено) Экспорт + + Разделитель = ПолучитьРазделительПути(); + + Результат = ДополнитьПуть(Путь1, Путь2, Разделитель); + + Если Путь3 <> Неопределено Тогда + Результат = ДополнитьПуть(Результат, Путь3, Разделитель); + КонецЕсли; + + Если Путь4 <> Неопределено Тогда + Результат = ДополнитьПуть(Результат, Путь4, Разделитель); + КонецЕсли; + + Если Путь5 <> Неопределено Тогда + Результат = ДополнитьПуть(Результат, Путь5, Разделитель); + КонецЕсли; + + Возврат Результат; + +КонецФункции + +// Удаляет файлы +// +// Параметры: +// Файлы - Массив из Файл +// - Массив из Строка +Процедура УдалитьВременныеФайлы(Файлы) Экспорт + + Если НЕ ЗначениеЗаполнено(Файлы) Тогда + Возврат; + КонецЕсли; + + Ошибки = Новый Массив(); + + Для Каждого УдаляемыйФайл Из Файлы Цикл + + Если ТипЗнч(УдаляемыйФайл) = Тип("Строка") Тогда + УдаляемыйФайл = Новый Файл(УдаляемыйФайл); + КонецЕсли; + + Попытка + Если УдаляемыйФайл.Существует() Тогда + + Если УдаляемыйФайл.ПолучитьТолькоЧтение() Тогда + УдаляемыйФайл.УстановитьТолькоЧтение(Ложь); + КонецЕсли; + + УдалитьФайлы(УдаляемыйФайл.ПолноеИмя); + + КонецЕсли; + Исключение + + Ошибки.Добавить(ЮТРегистрацияОшибокСлужебный.ПредставлениеОшибки("Удаление файла " + УдаляемыйФайл, ИнформацияОбОшибке())); + + КонецПопытки; + + КонецЦикла; + + Если ЗначениеЗаполнено(Ошибки) Тогда + ВызватьИсключение СтрСоединить(Ошибки, Символы.ПС); + КонецЕсли; + +КонецПроцедуры + +#КонецОбласти + +#Область СлужебныеПроцедурыИФункции + +#Если Клиент Тогда +Функция ОбработчикПолученияАтрибута(Файл, ИмяАтрибута, Обработчик, ЗначениеПоУмолчанию = Неопределено) + + Параметры = Новый Структура("Файл, ИмяАтрибута, Обработчик", Файл, ИмяАтрибута, Обработчик); + Параметры.Вставить("ЗначениеПоУмолчанию", ЗначениеПоУмолчанию); + + Возврат Новый ОписаниеОповещения("ПолучитьАтрибутФайла", ЭтотОбъект, Параметры); + +КонецФункции + +Процедура ПолучитьАтрибутФайла(Результат, Параметры) Экспорт + + Если НЕ Результат Тогда + ЮТАсинхроннаяОбработкаСлужебныйКлиент.ВызватьОбработчик(Параметры.Обработчик, Параметры.ЗначениеПоУмолчанию); + Возврат; + КонецЕсли; + + Если Параметры.ИмяАтрибута = "ЭтоКаталог" Тогда + Параметры.Файл.НачатьПроверкуЭтоКаталог(Параметры.Обработчик); + КонецЕсли; + +КонецПроцедуры +#КонецЕсли + +Функция ДополнитьПуть(Путь1, Путь2, Разделитель) + + Результат = Неопределено; + + Если ЗначениеЗаполнено(Путь1) И ЗначениеЗаполнено(Путь2) Тогда + + Если НЕ СтрЗаканчиваетсяНа(Путь1, Разделитель) И НЕ СтрНачинаетсяС(Разделитель, Путь2) Тогда + Результат = СтрШаблон("%1%2%3", Путь1, Разделитель, Путь2); + Иначе + Результат = Путь1 + Путь2; + КонецЕсли; + + ИначеЕсли ЗначениеЗаполнено(Путь1) Тогда + Результат = Путь1; + Иначе + Результат = Путь2; + КонецЕсли; + + Возврат Результат; + +КонецФункции + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТФильтрацияСлужебный.xml b/src/cfe/YAXUnit/CommonModules/ЮТФильтрацияСлужебный.xml new file mode 100644 index 0000000..d20c3ca --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТФильтрацияСлужебный.xml @@ -0,0 +1,23 @@ + + + + + ЮТФильтрацияСлужебный + + + ru + Фильтрация + + + + false + true + true + false + true + false + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТФильтрацияСлужебный/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТФильтрацияСлужебный/Ext/Module.bsl new file mode 100644 index 0000000..1b04441 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТФильтрацияСлужебный/Ext/Module.bsl @@ -0,0 +1,294 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область СлужебныйПрограммныйИнтерфейс + +Функция ЭтоПодходящееРасширение(ИмяРасширения) Экспорт + + Контекст = ЮТКонтекстСлужебный.КонтекстЧитателя(); + + НормализованноеИмяРасширения = УдалитьНедопустимыеСимволыИзСтрокиКакКлючаСтруктуры(ИмяРасширения); + + Возврат НЕ Контекст.Фильтр.ЕстьФильтрРасширений ИЛИ Контекст.Фильтр.Расширения.Свойство(НормализованноеИмяРасширения); + +КонецФункции + +Функция ЭтоПодходящийМодуль(ОписаниеМодуля) Экспорт + + Контекст = ЮТКонтекстСлужебный.КонтекстЧитателя(); + + Возврат ЗначениеЗаполнено(ОписаниеМодуля.Расширение) + И (НЕ Контекст.Фильтр.ЕстьФильтрМодулей ИЛИ Контекст.Фильтр.Модули.Свойство(ОписаниеМодуля.Имя)) + И ЭтоПодходящееРасширение(ОписаниеМодуля.Расширение); + +КонецФункции + +// Отфильтровать тестовые наборы. +// +// Параметры: +// ТестовыеНаборы - Массив из см. ЮТФабрикаСлужебный.ОписаниеТестовогоНабора - Тестовые наборы +// ОписаниеМодуля - Структура - Описание модуля, которому принадлежат наборы, см. ЮТФабрикаСлужебный.ОписаниеМодуля +// +// Возвращаемое значение: +// Массив из см. ЮТФабрикаСлужебный.ОписаниеТестовогоНабора - Отфильтрованные наборы +Функция ОтфильтроватьТестовыеНаборы(ТестовыеНаборы, ОписаниеМодуля) Экспорт + + Контекст = ЮТКонтекстСлужебный.КонтекстЧитателя(); + + Если НЕ Контекст.Фильтр.ЕстьФильтрТестов И НЕ Контекст.Фильтр.ЕстьФильтрКонтекстов Тогда + Возврат ТестовыеНаборы; + КонецЕсли; + + Результат = Новый Массив(); + + Если Контекст.Фильтр.ЕстьФильтрТестов Тогда + ДоступныеТестовыеМетоды = Новый Соответствие(); + + Для Каждого ОписаниеИмениТеста Из Контекст.Фильтр.Тесты Цикл + + Если СтрСравнить(ОписаниеИмениТеста.ИмяМодуля, ОписаниеМодуля.Имя) = 0 Тогда + ОписаниеИмениТеста.ИмяМетода = ВРег(ОписаниеИмениТеста.ИмяМетода); + + СохраненноеОписаниеИмени = ДоступныеТестовыеМетоды[ОписаниеИмениТеста.ИмяМетода]; + + Если СохраненноеОписаниеИмени = Неопределено И ОписаниеИмениТеста.Контекст = Неопределено Тогда + ДоступныеТестовыеМетоды.Вставить(ВРег(ОписаниеИмениТеста.ИмяМетода), ОписаниеИмениТеста); + ИначеЕсли СохраненноеОписаниеИмени = Неопределено Тогда + ОписаниеИмениТеста.Контекст = ЮТКоллекции.ЗначениеВМассиве(ОписаниеИмениТеста.Контекст); + ДоступныеТестовыеМетоды.Вставить(ВРег(ОписаниеИмениТеста.ИмяМетода), ОписаниеИмениТеста); + ИначеЕсли ОписаниеИмениТеста.Контекст = Неопределено Тогда + СохраненноеОписаниеИмени.Контекст = Неопределено; // Без фильтрации контекста теста, возьмом из самого теста контексты + ИначеЕсли СохраненноеОписаниеИмени.Контекст <> Неопределено Тогда + СохраненноеОписаниеИмени.Контекст.Добавить(ОписаниеИмениТеста.Контекст); + Иначе + // Если было имя теста без контекста, то будет вызов во всех контекстах + КонецЕсли; + КонецЕсли; + + КонецЦикла; + + КонецЕсли; + + Для Каждого Набор Из ТестовыеНаборы Цикл + + ОтфильтрованныйНабор = ЮТФабрикаСлужебный.ОписаниеТестовогоНабора(Набор.Имя); + ЗаполнитьЗначенияСвойств(ОтфильтрованныйНабор, Набор, , "Тесты"); + + Для Каждого Тест Из Набор.Тесты Цикл + + КонтекстыТеста = Неопределено; + + Если ДоступныеТестовыеМетоды <> Неопределено Тогда + ОписаниеИмениТеста = ДоступныеТестовыеМетоды[ВРег(Тест.Имя)]; + + Если ОписаниеИмениТеста = Неопределено Тогда + Продолжить; + КонецЕсли; + + КонтекстыТеста = ОписаниеИмениТеста.Контекст; + + КонецЕсли; + + Если КонтекстыТеста = Неопределено Тогда + КонтекстыТеста = Тест.КонтекстВызова; + КонецЕсли; + + Если Контекст.Фильтр.ЕстьФильтрКонтекстов Тогда + КонтекстыТеста = ЮТКоллекции.ПересечениеМассивов(КонтекстыТеста, Контекст.Фильтр.Контексты); + КонецЕсли; + + Если КонтекстыТеста.Количество() = 0 Тогда + // Возможно стоит такие выводить в лог с ошибкой "по переданным параметрам контекст теста не определен" + Продолжить; + КонецЕсли; + + ОтфильтрованныйТест = ЮТФабрикаСлужебный.ОписаниеТеста(Тест.Имя, "", ""); + ЗаполнитьЗначенияСвойств(ОтфильтрованныйТест, Тест, , "КонтекстВызова"); + ОтфильтрованныйТест.КонтекстВызова = КонтекстыТеста; + + ОтфильтрованныйНабор.Тесты.Добавить(ОтфильтрованныйТест); + + КонецЦикла; + + Если ОтфильтрованныйНабор.Тесты.Количество() Тогда + Результат.Добавить(ОтфильтрованныйНабор); + КонецЕсли; + + КонецЦикла; + + Возврат Результат; + +КонецФункции + +// Фильтр +// Конструктур фильтра поиска тестовых методов +// +// Возвращаемое значение: +// Структура - Фильтр: +// * Расширения - Структура - Имена расширений +// * Модули - Структура - Имена модулей +// * Наборы - Массив из Строка - Имена тестовых наборов +// * Теги - Массив из Строка +// * Контексты - Массив из Строка - Контексты вызова тестовых методов +// * Тесты - Массив из см. ОписаниеИмениТеста - Список путей к тестовым методам +// * Пути - Массив из Строка +Функция Фильтр() Экспорт + + //@skip-check structure-consructor-too-many-keys + Фильтр = Новый Структура("Расширения, Модули, Наборы, Теги, Контексты, Пути, Тесты"); + + Фильтр.Расширения = Новый Структура(); + Фильтр.Модули = Новый Структура(); + Фильтр.Теги = Новый Массив(); + Фильтр.Контексты = Новый Массив(); + Фильтр.Наборы = Новый Массив(); + Фильтр.Пути = Новый Массив(); + Фильтр.Тесты = Новый Массив(); + + //@skip-check constructor-function-return-section + Возврат Фильтр; + +КонецФункции + +Процедура УстановитьКонтекст(ПараметрыЗапускаТестов) Экспорт + + Расширения = ЮТКоллекции.ЗначениеСтруктуры(ПараметрыЗапускаТестов.filter, "extensions", Новый Массив); + Модули = ЮТКоллекции.ЗначениеСтруктуры(ПараметрыЗапускаТестов.filter, "modules", Новый Массив); + Контексты = ЮТКоллекции.ЗначениеСтруктуры(ПараметрыЗапускаТестов.filter, "contexts"); + Тесты = ЮТКоллекции.ЗначениеСтруктуры(ПараметрыЗапускаТестов.filter, "tests", Новый Массив); + + Теги = ЮТКоллекции.ЗначениеСтруктуры(ПараметрыЗапускаТестов.filter, "tags", Новый Массив); + // TODO: Подумать в каком формате задать наборы - ИмяМодуля.Набор, Набор или другой вариант + Наборы = ЮТКоллекции.ЗначениеСтруктуры(ПараметрыЗапускаТестов.filter, "suites", Новый Массив); + // TODO: Обработка путей в формате: Модуль.ИмяТеста, ИмяТеста - метод, параметры, контекст + // ОМ_ЮТУтверждения.Что[0: 1].Сервер, ОМ_ЮТУтверждения.Что[1: Структура].Сервер + Пути = ЮТКоллекции.ЗначениеСтруктуры(ПараметрыЗапускаТестов.filter, "paths", Новый Массив); + + Фильтр = Фильтр(); + + Фильтр.Расширения = МассивВСтруктуру(Расширения); + Фильтр.Модули = МассивВСтруктуру(Модули); + + Если Контексты = Неопределено Тогда + Фильтр.Контексты = ЮТФабрикаСлужебный.КонтекстыПриложения(); + Иначе + Фильтр.Контексты = Контексты; + КонецЕсли; + + Если ЗначениеЗаполнено(Теги) Тогда + Фильтр.Теги = Теги; + КонецЕсли; + + Если ЗначениеЗаполнено(Наборы) Тогда + Фильтр.Наборы = Наборы; + КонецЕсли; + + Если ЗначениеЗаполнено(Пути) Тогда + Фильтр.Пути = Пути; + КонецЕсли; + + МодулиТестов = Новый Структура(); + + Если ЗначениеЗаполнено(Тесты) Тогда + Для Каждого ПолноеИмяТеста Из Тесты Цикл + Описание = ОписаниеИмениТеста(ПолноеИмяТеста); + Фильтр.Тесты.Добавить(Описание); + МодулиТестов.Вставить(Описание.ИмяМодуля, Истина); + КонецЦикла; + КонецЕсли; + + Если МодулиТестов.Количество() И Фильтр.Модули.Количество() = 0 Тогда + + Фильтр.Модули = МодулиТестов; + + ИначеЕсли МодулиТестов.Количество() Тогда + + Модули = Новый Структура(); + + Для Каждого Элемент Из Фильтр.Модули Цикл + Если МодулиТестов.Свойство(Элемент.Ключ) Тогда + Модули.Вставить(Элемент.Ключ, Истина); + КонецЕсли; + КонецЦикла; + + Фильтр.Модули = Модули; + + КонецЕсли; + + Фильтр.Вставить("ЕстьФильтрРасширений", Фильтр.Расширения.Количество() > 0); + Фильтр.Вставить("ЕстьФильтрМодулей", МодулиТестов.Количество() ИЛИ Фильтр.Модули.Количество()); + Фильтр.Вставить("ЕстьФильтрТестов", Фильтр.Тесты.Количество()); + Фильтр.Вставить("ЕстьФильтрКонтекстов", ЗначениеЗаполнено(Фильтр.Контексты)); + + ЮТКонтекстСлужебный.УстановитьКонтекстЧитателя(Новый Структура("Фильтр", Фильтр)); + +КонецПроцедуры + +#КонецОбласти + +#Область СлужебныеПроцедурыИФункции + +Функция МассивВСтруктуру(Значения) + + Результат = Новый Структура(); + + Если НЕ ЗначениеЗаполнено(Значения) Тогда + Возврат Результат; + КонецЕсли; + + Для Каждого Значение Из Значения Цикл + + НормализованноеЗначение = УдалитьНедопустимыеСимволыИзСтрокиКакКлючаСтруктуры(Значение); + Результат.Вставить(НормализованноеЗначение); + + КонецЦикла; + + Возврат Результат; + +КонецФункции + +Функция УдалитьНедопустимыеСимволыИзСтрокиКакКлючаСтруктуры(СтрокаКакКлюч) + // TODO Переработать. Не модифицировать значение + Возврат СтрЗаменить(СтрокаКакКлюч, ".", ""); +КонецФункции + +Функция ОписаниеИмениТеста(Путь) + + Части = СтрРазделить(Путь, "."); + + Если Части.Количество() <= 1 ИЛИ Части.Количество() > 3 Тогда + ВызватьИсключение СтрШаблон("Не корректный формат пути к тесту `%1`, должен быть в формате `ИмяМодуля.ИмяМетода{.Контекст}`", Путь); + КонецЕсли; + + Описание = Новый Структура("ИмяМодуля, ИмяМетода, Контекст"); + + Для Инд = 0 По Части.ВГраница() Цикл + Части[Инд] = СокрЛП(Части[Инд]); + КонецЦикла; + + Описание.ИмяМодуля = Части[0]; + Описание.ИмяМетода = Части[1]; + Если Части.Количество() > 2 Тогда + Описание.Контекст = Части[2]; + КонецЕсли; + + Возврат Описание; + +КонецФункции + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТЧитательСлужебный.xml b/src/cfe/YAXUnit/CommonModules/ЮТЧитательСлужебный.xml new file mode 100644 index 0000000..62d14a7 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТЧитательСлужебный.xml @@ -0,0 +1,23 @@ + + + + + ЮТЧитательСлужебный + + + ru + Загрузчик тестов + + + + false + true + true + false + true + false + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТЧитательСлужебный/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТЧитательСлужебный/Ext/Module.bsl new file mode 100644 index 0000000..73c2206 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТЧитательСлужебный/Ext/Module.bsl @@ -0,0 +1,235 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область СлужебныйПрограммныйИнтерфейс + +// ЗагрузитьТесты +// Читает наборы тестов (тестовые модули) из расширений +// Параметры: +// ПараметрыЗапускаТестов - см. ЮТФабрика.ПараметрыЗапуска +// +// Возвращаемое значение: +// Массив из см. ЮТФабрикаСлужебный.ОписаниеТестовогоМодуля - Набор описаний тестовых модулей, которые содержат информацию о запускаемых тестах +Функция ЗагрузитьТесты(ПараметрыЗапускаТестов) Экспорт + + Результат = Новый Массив; + + ЮТФильтрацияСлужебный.УстановитьКонтекст(ПараметрыЗапускаТестов); + + Для Каждого МетаданныеМодуля Из ТестовыеМодули() Цикл + + ОписаниеТестовогоМодуля = ТестовыеНаборыМодуля(МетаданныеМодуля, ПараметрыЗапускаТестов); + + Если ОписаниеТестовогоМодуля = Неопределено Тогда + Продолжить; + КонецЕсли; + + Результат.Добавить(ОписаниеТестовогоМодуля); + + КонецЦикла; + + Возврат Результат; + +КонецФункции + +// ПрочитатьНаборТестов +// Читает набор тестов из модуля +// Параметры: +// МетаданныеМодуля - см. ЮТФабрикаСлужебный.ОписаниеМодуля +// +// Возвращаемое значение: +// - Неопределено - Если это не тестовый модуль +// - см. ЮТФабрикаСлужебный.ОписаниеТестовогоМодуля +Функция ИсполняемыеСценарииМодуля(Знач МетаданныеМодуля) Экспорт + + ЭтоТестовыйМодуль = Истина; + ОписаниеТестовогоМодуля = ЮТФабрикаСлужебный.ОписаниеТестовогоМодуля(МетаданныеМодуля, Новый Массив); + + ЮТТестыСлужебный.ПередЧтениемСценариевМодуля(МетаданныеМодуля); + + ПолноеИмяМетода = МетаданныеМодуля.Имя + "." + ИмяМетодаСценариев(); + Ошибка = ЮТМетодыСлужебный.ВыполнитьМетод(ПолноеИмяМетода); + + Если Ошибка <> Неопределено Тогда + + ТипыОшибок = ЮТФабрикаСлужебный.ТипыОшибок(); + ТипОшибки = ЮТРегистрацияОшибокСлужебный.ТипОшибки(Ошибка, ПолноеИмяМетода); + + Если ТипОшибки = ТипыОшибок.ТестНеРеализован Тогда + ЭтоТестовыйМодуль = Ложь; + Ошибка = Неопределено; + ИначеЕсли ТипОшибки = ТипыОшибок.МалоПараметров Тогда + Ошибка = ЮТМетодыСлужебный.ВыполнитьМетод(ПолноеИмяМетода, ЮТКоллекции.ЗначениеВМассиве(Неопределено)); + ЮТОбщий.СообщитьПользователю("Используется устаревшая сигнатура метода `ИсполняемыеСценарии`, метод не должен принимать параметров."); + КонецЕсли; + + КонецЕсли; + + Если Ошибка <> Неопределено Тогда + + НаборПоУмолчанию = ЮТФабрикаСлужебный.ОписаниеТестовогоНабора(МетаданныеМодуля.Имя); + ЮТРегистрацияОшибокСлужебный.ЗарегистрироватьОшибкуЧтенияТестов(НаборПоУмолчанию, "Ошибка формирования списка тестовых методов", Ошибка); + ОписаниеТестовогоМодуля.НаборыТестов.Добавить(НаборПоУмолчанию); + + ИначеЕсли ЭтоТестовыйМодуль Тогда + + ЮТТестыСлужебный.ПослеЧтенияСценариевМодуля(); + Сценарии = ЮТТестыСлужебный.СценарииМодуля(); + + УдалитьНастройкиМодуляИзПервогоНабора(Сценарии); // TODO Нужен рефакторинг + + ОписаниеТестовогоМодуля.НаборыТестов = ЮТФильтрацияСлужебный.ОтфильтроватьТестовыеНаборы(Сценарии.ТестовыеНаборы, МетаданныеМодуля); + ОписаниеТестовогоМодуля.НастройкиВыполнения = Сценарии.НастройкиВыполнения; + + Иначе + + ОписаниеТестовогоМодуля = Неопределено; + + КонецЕсли; + + Возврат ОписаниеТестовогоМодуля; + +КонецФункции + +// ЭтоТестовыйМодуль +// Проверяет, является ли модуль модулем с тестами +// Параметры: +// МетаданныеМодуля - Структура - Описание метаданных модуля, см. ЮТФабрикаСлужебный.ОписаниеМодуля +// +// Возвращаемое значение: +// Булево - Этот модуль содержит тесты +Функция ЭтоТестовыйМодуль(МетаданныеМодуля) Экспорт + + Если МетаданныеМодуля.Глобальный Тогда + Возврат Ложь; + КонецЕсли; + +#Если Сервер Тогда + Возврат ЮТМетодыСлужебный.МетодМодуляСуществует(МетаданныеМодуля.Имя, ИмяМетодаСценариев()); +#КонецЕсли + +#Если ТолстыйКлиентУправляемоеПриложение ИЛИ ТонкийКлиент Тогда + Если МетаданныеМодуля.КлиентУправляемоеПриложение Тогда + Возврат ЮТМетодыСлужебный.МетодМодуляСуществует(МетаданныеМодуля.Имя, ИмяМетодаСценариев()); + КонецЕсли; +#КонецЕсли + +#Если ТолстыйКлиентОбычноеПриложение Тогда + Если МетаданныеМодуля.КлиентОбычноеПриложение Тогда + Возврат ЮТМетодыСлужебный.МетодМодуляСуществует(МетаданныеМодуля.Имя, ИмяМетодаСценариев()); + КонецЕсли; +#КонецЕсли + + Если МетаданныеМодуля.Сервер Тогда + //@skip-check unknown-method-property + Возврат ЮТЧитательСлужебныйВызовСервера.ЭтоТестовыйМодуль(МетаданныеМодуля); + Иначе + Возврат Ложь; + КонецЕсли; + +КонецФункции + +#КонецОбласти + +#Область СлужебныеПроцедурыИФункции + +Функция ИмяМетодаСценариев() + + Возврат "ИсполняемыеСценарии"; + +КонецФункции + +// ТестовыеМодули +// Возвращает описания модулей, содержащих тесты +// Возвращаемое значение: +// Массив из см. ЮТМетаданныеСлужебныйВызовСервера.МетаданныеМодуля - Тестовые модули +Функция ТестовыеМодули() + + ТестовыеМодули = Новый Массив; + + //@skip-check unknown-method-property + МодулиРасширения = ЮТМетаданныеСлужебныйВызовСервера.МодулиРасширений(); + + Для Каждого ОписаниеМодуля Из МодулиРасширения Цикл + + Если ЮТФильтрацияСлужебный.ЭтоПодходящийМодуль(ОписаниеМодуля) И ЭтоТестовыйМодуль(ОписаниеМодуля) Тогда + + ТестовыеМодули.Добавить(ОписаниеМодуля); + + КонецЕсли; + + КонецЦикла; + + Возврат ТестовыеМодули; + +КонецФункции + +Функция ТестовыеНаборыМодуля(МетаданныеМодуля, ПараметрыЗапуска) + + // TODO Фильтрация по путям + ОписаниеМодуля = Неопределено; + +#Если ТолстыйКлиентОбычноеПриложение ИЛИ ТолстыйКлиентУправляемоеПриложение Тогда + Если МетаданныеМодуля.КлиентОбычноеПриложение ИЛИ МетаданныеМодуля.КлиентУправляемоеПриложение Тогда + + ОписаниеМодуля = ИсполняемыеСценарииМодуля(МетаданныеМодуля); + + ИначеЕсли МетаданныеМодуля.Сервер Тогда + + ОписаниеМодуля = ЮТЧитательСлужебныйВызовСервера.ИсполняемыеСценарииМодуля(МетаданныеМодуля); + ЮТЛогированиеСлужебный.ВывестиСерверныеСообщения(); + + КонецЕсли; +#ИначеЕсли Сервер Тогда + Если МетаданныеМодуля.Сервер Тогда + + ОписаниеМодуля = ИсполняемыеСценарииМодуля(МетаданныеМодуля); + + Иначе + + ВызватьИсключение "Чтение списка тестов модуля в недоступном контексте"; + + КонецЕсли; +#ИначеЕсли Клиент Тогда + Если МетаданныеМодуля.КлиентУправляемоеПриложение Тогда + + ОписаниеМодуля = ИсполняемыеСценарииМодуля(МетаданныеМодуля); + + ИначеЕсли МетаданныеМодуля.Сервер Тогда + + ОписаниеМодуля = ЮТЧитательСлужебныйВызовСервера.ИсполняемыеСценарииМодуля(МетаданныеМодуля); + ЮТЛогированиеСлужебный.ВывестиСерверныеСообщения(); + + КонецЕсли; +#КонецЕсли + + Возврат ОписаниеМодуля; + +КонецФункции + +Процедура УдалитьНастройкиМодуляИзПервогоНабора(СценарииМодуля) + + НастройкиВыполнения = ЮТКоллекции.СкопироватьРекурсивно(СценарииМодуля.НастройкиВыполнения); + + СценарииМодуля.НастройкиВыполнения.Очистить(); + + СценарииМодуля.НастройкиВыполнения = НастройкиВыполнения; + +КонецПроцедуры + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТЧитательСлужебныйВызовСервера.xml b/src/cfe/YAXUnit/CommonModules/ЮТЧитательСлужебныйВызовСервера.xml new file mode 100644 index 0000000..2290747 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТЧитательСлужебныйВызовСервера.xml @@ -0,0 +1,23 @@ + + + + + ЮТЧитательСлужебныйВызовСервера + + + ru + Загрузчик тестов (сервер) + + + + false + false + true + false + false + true + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТЧитательСлужебныйВызовСервера/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТЧитательСлужебныйВызовСервера/Ext/Module.bsl new file mode 100644 index 0000000..1e3cf45 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТЧитательСлужебныйВызовСервера/Ext/Module.bsl @@ -0,0 +1,34 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область СлужебныйПрограммныйИнтерфейс + +// См. ЮТЧитательСлужебный.ИсполняемыеСценарииМодуля +Функция ИсполняемыеСценарииМодуля(Знач МетаданныеМодуля) Экспорт + + Возврат ЮТЧитательСлужебный.ИсполняемыеСценарииМодуля(МетаданныеМодуля); + +КонецФункции + +Функция ЭтоТестовыйМодуль(МетаданныеМодуля) Экспорт + + Возврат ЮТЧитательСлужебный.ЭтоТестовыйМодуль(МетаданныеМодуля); + +КонецФункции + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonModules/ЮТест.xml b/src/cfe/YAXUnit/CommonModules/ЮТест.xml new file mode 100644 index 0000000..c7e24cf --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТест.xml @@ -0,0 +1,23 @@ + + + + + ЮТест + + + ru + Тест + + + + false + true + true + false + true + false + false + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonModules/ЮТест/Ext/Module.bsl b/src/cfe/YAXUnit/CommonModules/ЮТест/Ext/Module.bsl new file mode 100644 index 0000000..b67ec89 --- /dev/null +++ b/src/cfe/YAXUnit/CommonModules/ЮТест/Ext/Module.bsl @@ -0,0 +1,206 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +///////////////////////////////////////////////////////////////////////////////// +// Основной модуль для запуска тестирования +///////////////////////////////////////////////////////////////////////////////// +#Область ПрограммныйИнтерфейс + +// Возвращает API формирования утверждения для проверки теста. +// +// Параметры: +// ПроверяемоеЗначение - Произвольный - Проверяемое фактическое значение +// Сообщение - Строка - Описание проверки, которое будет выведено при возникновении ошибки +// +// Возвращаемое значение: +// ОбщийМодуль - Утверждения, см. ЮТУтверждения +Функция ОжидаетЧто(ПроверяемоеЗначение, Сообщение = "") Экспорт + + Возврат ЮТУтверждения.Что(ПроверяемоеЗначение, Сообщение); + +КонецФункции + +// Возвращает API формирования утверждения для проверки данных базы. +// +// Параметры: +// ИмяТаблицы - Строка - Имя таблицы базы, например, `Справочник.Пользователи`, `Документ.ПКО`, `РегистрСведений.ИнформацияОбОшибках` +// Сообщение - Строка - Описание проверки, которое будет выведено при возникновении ошибки +// +// Возвращаемое значение: +// ОбщийМодуль - Утверждения для проверки данных базы, см. ЮТУтвержденияИБ +Функция ОжидаетЧтоТаблицаБазы(ИмяТаблицы, Сообщение = "") Экспорт + + Возврат ЮТУтвержденияИБ.ЧтоТаблица(ИмяТаблицы, Сообщение); + +КонецФункции + +// Возвращает API для работы с тестовыми данными. +// +// Возвращаемое значение: +// ОбщийМодуль - Данные, см. ЮТТестовыеДанные. +Функция Данные() Экспорт + + Возврат ЮТТестовыеДанные; + +КонецФункции + +// Возвращает API для формирования предикатов/утверждений, которые могут быть использованы для проверки коллекций. +// +// Параметры: +// Условия - Структура, Соответствие из Произвольный - Набор условий, которыми инициализируется предикат +// Ключ - Строка - Имя реквизита +// Значение - Произвольный - Значение, которому должен быть равен реквизит +// +// Возвращаемое значение: +// ОбщийМодуль - См. ЮТПредикаты. +Функция Предикат(Условия = Неопределено) Экспорт + + Возврат ЮТПредикаты.Инициализировать(Условия); + +КонецФункции + +// Конструктор вариантов прогона теста. +// +// Используется для формирования набора различных параметров выполнения. +// Параметры: +// Реквизиты - Строка - Список реквизитов варианта разделенных запятой +// +// Возвращаемое значение: +// ОбщийМодуль - Варианты, см. ЮТКонструкторВариантов. +Функция Варианты(Реквизиты) Экспорт + + Возврат ЮТКонструкторВариантов.Варианты(Реквизиты); + +КонецФункции + +// Умный контекст, в который можно сохранять и получать из него промежуточные данные +// Этот контекст работает с см. КонтекстТеста, см. КонтекстТестовогоНабора и см. КонтекстМодуля. +// При получении значения оно ущется во всех 3 контекста поочереди. +// При установке значения, оно устанавливается в текущий контекст, например, в событии перед тестовым наборов в м. КонтекстТестовогоНабора +// +// Возвращаемое значение: +// ОбщийМодуль - Контекст теста, см. ЮТКонтекстТеста +Функция Контекст() Экспорт + + Возврат ЮТКонтекстТеста; + +КонецФункции + +// Пропустить выполнение теста. +// +// Используется если тест выполняется в неподходящих условиях и не нужно его выполнять, но отразить в отчете требуется. +// Параметры: +// Сообщение - Строка, Неопределено - Сообщение +Процедура Пропустить(Сообщение = Неопределено) Экспорт + + ЮТРегистрацияОшибокСлужебный.Пропустить(Сообщение); + +КонецПроцедуры + +// Возвращает структуру, в которой можно хранить данные используемые в тесте. +// +// Данные живут в рамках одного теста, но доступны в обработчиках событий `ПередКаждымТестом` и `ПослеКаждогоТеста`. +// +// Например, в контекст можно помещать создаваемые данные, что бы освободить/удалить их в обработчике `ПослеКаждогоТеста`. +// Возвращаемое значение: +// - Структура - Контекст теста +// - Неопределено - Если метод вызывается за рамками теста +Функция КонтекстТеста() Экспорт + + //@skip-check constructor-function-return-section + Возврат ЮТКонтекстСлужебный.КонтекстТеста(); + +КонецФункции + +// Возвращает структуру, в которой можно хранить данные используемые в тестах набора. +// +// Данные живут в рамках одного набора тестов (данные между клиентом и сервером не синхронизируются). +// Доступны в каждом тесте набора и в обработчиках событий: +// + `ПередТестовымНабором` +// + `ПослеТестовогоНабора` +// + `ПередКаждымТестом` +// + `ПослеКаждогоТеста` +// +// Например, в контекст можно помещать создаваемые данные, что бы освободить/удалить их в обработчике `ПослеКаждогоТеста`. +// Возвращаемое значение: +// - Структура - Контекст набора тестов +// - Неопределено - Если метод вызывается за рамками тестового набора +Функция КонтекстТестовогоНабора() Экспорт + + //@skip-check constructor-function-return-section + Возврат ЮТКонтекстСлужебный.КонтекстНабора(); + +КонецФункции + +// Возвращает структуру, в которой можно хранить данные используемые в тестах модуля. +// +// Данные живут в рамках одного тестового модуля (данные между клиентом и сервером не синхронизируются). +// Доступны в каждом тесте модуля и в обработчиках событий. +// +// Например, в контекст можно помещать создаваемые данные, что бы освободить/удалить их в обработчике `ПослеВсехТестов`. +// Возвращаемое значение: +// - Структура - Контекст тестового модуля +// - Неопределено - Если метод вызывается за рамками тестового модуля +Функция КонтекстМодуля() Экспорт + + //@skip-check constructor-function-return-section + Возврат ЮТКонтекстСлужебный.КонтекстМодуля(); + +КонецФункции + +// Преостанавливает поток выполнения на указанное количество секунд +// +// Параметры: +// Время - Число - Продолжительность паузы в секундах, возможно указывать дробное значение +Процедура Пауза(Время) Экспорт + + ЮТОбщий.Пауза(Время); + +КонецПроцедуры + +// Выводит сообщение в консоль (stdout) приложения +// +// Параметры: +// Сообщение - Строка - Выводимое сообщение +Процедура ВывестиВКонсоль(Сообщение) Экспорт + + ЮТОбщий.ВывестиВКонсоль(Сообщение); + +КонецПроцедуры + +// Добавляет сообщение в лог исполнения теста. +// +// Параметры: +// ТекстСообщения - Строка - Текст сообщения +Процедура ДобавитьСообщение(ТекстСообщения) Экспорт + + ЮТЛогИсполненияТестаСлужебный.ДобавитьСообщение(ТекстСообщения); + +КонецПроцедуры + +// Добавляет предупреждение в лог исполнения теста. +// +// Параметры: +// ТекстПредупреждения - Строка - Текст предупреждения +Процедура ДобавитьПредупреждение(ТекстПредупреждения) Экспорт + + ЮТЛогИсполненияТестаСлужебный.ДобавитьПредупреждение(ТекстПредупреждения); + +КонецПроцедуры + +#КонецОбласти diff --git a/src/cfe/YAXUnit/CommonPictures/ЮТЗапустить.xml b/src/cfe/YAXUnit/CommonPictures/ЮТЗапустить.xml new file mode 100644 index 0000000..9d6a5d5 --- /dev/null +++ b/src/cfe/YAXUnit/CommonPictures/ЮТЗапустить.xml @@ -0,0 +1,17 @@ + + + + + ЮТЗапустить + + + ru + Запустить + + + + false + false + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonPictures/ЮТЗапустить/Ext/Picture.xml b/src/cfe/YAXUnit/CommonPictures/ЮТЗапустить/Ext/Picture.xml new file mode 100644 index 0000000..0da1845 --- /dev/null +++ b/src/cfe/YAXUnit/CommonPictures/ЮТЗапустить/Ext/Picture.xml @@ -0,0 +1,7 @@ + + + + Picture.svg + false + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonPictures/ЮТЗапустить/Ext/Picture/Picture.svg b/src/cfe/YAXUnit/CommonPictures/ЮТЗапустить/Ext/Picture/Picture.svg new file mode 100644 index 0000000..2f6dafb --- /dev/null +++ b/src/cfe/YAXUnit/CommonPictures/ЮТЗапустить/Ext/Picture/Picture.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/cfe/YAXUnit/CommonPictures/ЮТНеизвестный.xml b/src/cfe/YAXUnit/CommonPictures/ЮТНеизвестный.xml new file mode 100644 index 0000000..42713a8 --- /dev/null +++ b/src/cfe/YAXUnit/CommonPictures/ЮТНеизвестный.xml @@ -0,0 +1,17 @@ + + + + + ЮТНеизвестный + + + ru + Неизвестный + + + + false + false + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonPictures/ЮТНеизвестный/Ext/Picture.xml b/src/cfe/YAXUnit/CommonPictures/ЮТНеизвестный/Ext/Picture.xml new file mode 100644 index 0000000..0da1845 --- /dev/null +++ b/src/cfe/YAXUnit/CommonPictures/ЮТНеизвестный/Ext/Picture.xml @@ -0,0 +1,7 @@ + + + + Picture.svg + false + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonPictures/ЮТНеизвестный/Ext/Picture/Picture.svg b/src/cfe/YAXUnit/CommonPictures/ЮТНеизвестный/Ext/Picture/Picture.svg new file mode 100644 index 0000000..6c4094e --- /dev/null +++ b/src/cfe/YAXUnit/CommonPictures/ЮТНеизвестный/Ext/Picture/Picture.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/cfe/YAXUnit/CommonPictures/ЮТОшибка.xml b/src/cfe/YAXUnit/CommonPictures/ЮТОшибка.xml new file mode 100644 index 0000000..6ada654 --- /dev/null +++ b/src/cfe/YAXUnit/CommonPictures/ЮТОшибка.xml @@ -0,0 +1,17 @@ + + + + + ЮТОшибка + + + ru + Ошибка + + + + false + false + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonPictures/ЮТОшибка/Ext/Picture.xml b/src/cfe/YAXUnit/CommonPictures/ЮТОшибка/Ext/Picture.xml new file mode 100644 index 0000000..0da1845 --- /dev/null +++ b/src/cfe/YAXUnit/CommonPictures/ЮТОшибка/Ext/Picture.xml @@ -0,0 +1,7 @@ + + + + Picture.svg + false + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonPictures/ЮТОшибка/Ext/Picture/Picture.svg b/src/cfe/YAXUnit/CommonPictures/ЮТОшибка/Ext/Picture/Picture.svg new file mode 100644 index 0000000..30a9406 --- /dev/null +++ b/src/cfe/YAXUnit/CommonPictures/ЮТОшибка/Ext/Picture/Picture.svg @@ -0,0 +1,6 @@ + + + + diff --git a/src/cfe/YAXUnit/CommonPictures/ЮТПерезапуститьУпавшие.xml b/src/cfe/YAXUnit/CommonPictures/ЮТПерезапуститьУпавшие.xml new file mode 100644 index 0000000..5ea959e --- /dev/null +++ b/src/cfe/YAXUnit/CommonPictures/ЮТПерезапуститьУпавшие.xml @@ -0,0 +1,17 @@ + + + + + ЮТПерезапуститьУпавшие + + + ru + Перезапустить упавшие + + + + false + false + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonPictures/ЮТПерезапуститьУпавшие/Ext/Picture.xml b/src/cfe/YAXUnit/CommonPictures/ЮТПерезапуститьУпавшие/Ext/Picture.xml new file mode 100644 index 0000000..0da1845 --- /dev/null +++ b/src/cfe/YAXUnit/CommonPictures/ЮТПерезапуститьУпавшие/Ext/Picture.xml @@ -0,0 +1,7 @@ + + + + Picture.svg + false + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonPictures/ЮТПерезапуститьУпавшие/Ext/Picture/Picture.svg b/src/cfe/YAXUnit/CommonPictures/ЮТПерезапуститьУпавшие/Ext/Picture/Picture.svg new file mode 100644 index 0000000..9cbd45c --- /dev/null +++ b/src/cfe/YAXUnit/CommonPictures/ЮТПерезапуститьУпавшие/Ext/Picture/Picture.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + diff --git a/src/cfe/YAXUnit/CommonPictures/ЮТПодсистема.xml b/src/cfe/YAXUnit/CommonPictures/ЮТПодсистема.xml new file mode 100644 index 0000000..86cc296 --- /dev/null +++ b/src/cfe/YAXUnit/CommonPictures/ЮТПодсистема.xml @@ -0,0 +1,17 @@ + + + + + ЮТПодсистема + + + ru + Картинка подсистемы ЮТДвижок + + + + false + false + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonPictures/ЮТПодсистема/Ext/Picture.xml b/src/cfe/YAXUnit/CommonPictures/ЮТПодсистема/Ext/Picture.xml new file mode 100644 index 0000000..dba17d4 --- /dev/null +++ b/src/cfe/YAXUnit/CommonPictures/ЮТПодсистема/Ext/Picture.xml @@ -0,0 +1,7 @@ + + + + Picture.png + false + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonPictures/ЮТПодсистема/Ext/Picture/Picture.png b/src/cfe/YAXUnit/CommonPictures/ЮТПодсистема/Ext/Picture/Picture.png new file mode 100644 index 0000000000000000000000000000000000000000..649e965bf5757ddf26d534e398754a0d510909f3 GIT binary patch literal 706 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf66p}rHd>I(3)EF2VS{N990fib~ zFff!FFfhDIU|_JC!N4G1FlSew4N!t9$=lt9;eUJonf*W>dx@v7EBkX+E*2dDXLnnm zLdIpDE{-7@=T*;~^$rP?IPma(^*PDsw~uLFY)o2m#zgj3gwzg>MXp=A{xwWntJO43 zZ*f?Xv+3y!;fsetbCr}yKC?sMtx;&-uWOT~#hE>G<-FqN7&Ek|n*}d5gMpj1^`t0PNCT6Z(z$nW0;^Bt$ljXM= z)tB}dM=PKIW*+|eu7=>hGbMemJC0AuJoeG-envBIP+e`{v=Xxtna6se#TV}=@vgG{ zs!*sd>1S|~QPkJ?pvYl99X3Hh2IWVBz07MKeLTV@!qUvRwZUo4sznW2d@@oe&Ehq^ z?rvvrw|e?ZQ)ku0W^EnzX6;Q~oA00$k)j!>W{|hT)oK) z9Q&5+dp55%HfzoThql;nyVKfLTsM_G=Kthk_n%q!*czo5?ujdak*HeY8c~vxSdwa$ zT$Bo=7>o>zjCBo6bqx(d3{0#{OsotnwG9lc3=9%(7k)$0kei>9nO2EggJ9c9FQ5hu lxD6$lxv9k^iMa)sdJN4Vmedr^cm&kL;OXk;vd$@?2>>ga6B_^k literal 0 HcmV?d00001 diff --git a/src/cfe/YAXUnit/CommonPictures/ЮТПропущен.xml b/src/cfe/YAXUnit/CommonPictures/ЮТПропущен.xml new file mode 100644 index 0000000..ec89fe9 --- /dev/null +++ b/src/cfe/YAXUnit/CommonPictures/ЮТПропущен.xml @@ -0,0 +1,17 @@ + + + + + ЮТПропущен + + + ru + Пропущен + + + + false + false + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonPictures/ЮТПропущен/Ext/Picture.xml b/src/cfe/YAXUnit/CommonPictures/ЮТПропущен/Ext/Picture.xml new file mode 100644 index 0000000..0da1845 --- /dev/null +++ b/src/cfe/YAXUnit/CommonPictures/ЮТПропущен/Ext/Picture.xml @@ -0,0 +1,7 @@ + + + + Picture.svg + false + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonPictures/ЮТПропущен/Ext/Picture/Picture.svg b/src/cfe/YAXUnit/CommonPictures/ЮТПропущен/Ext/Picture/Picture.svg new file mode 100644 index 0000000..85123af --- /dev/null +++ b/src/cfe/YAXUnit/CommonPictures/ЮТПропущен/Ext/Picture/Picture.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/cfe/YAXUnit/CommonPictures/ЮТСравнить.xml b/src/cfe/YAXUnit/CommonPictures/ЮТСравнить.xml new file mode 100644 index 0000000..c6393ba --- /dev/null +++ b/src/cfe/YAXUnit/CommonPictures/ЮТСравнить.xml @@ -0,0 +1,17 @@ + + + + + ЮТСравнить + + + ru + Сравнить + + + + false + false + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonPictures/ЮТСравнить/Ext/Picture.xml b/src/cfe/YAXUnit/CommonPictures/ЮТСравнить/Ext/Picture.xml new file mode 100644 index 0000000..0da1845 --- /dev/null +++ b/src/cfe/YAXUnit/CommonPictures/ЮТСравнить/Ext/Picture.xml @@ -0,0 +1,7 @@ + + + + Picture.svg + false + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonPictures/ЮТСравнить/Ext/Picture/Picture.svg b/src/cfe/YAXUnit/CommonPictures/ЮТСравнить/Ext/Picture/Picture.svg new file mode 100644 index 0000000..eba7e61 --- /dev/null +++ b/src/cfe/YAXUnit/CommonPictures/ЮТСравнить/Ext/Picture/Picture.svg @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonPictures/ЮТУпал.xml b/src/cfe/YAXUnit/CommonPictures/ЮТУпал.xml new file mode 100644 index 0000000..1299874 --- /dev/null +++ b/src/cfe/YAXUnit/CommonPictures/ЮТУпал.xml @@ -0,0 +1,17 @@ + + + + + ЮТУпал + + + ru + Упал + + + + false + false + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonPictures/ЮТУпал/Ext/Picture.xml b/src/cfe/YAXUnit/CommonPictures/ЮТУпал/Ext/Picture.xml new file mode 100644 index 0000000..0da1845 --- /dev/null +++ b/src/cfe/YAXUnit/CommonPictures/ЮТУпал/Ext/Picture.xml @@ -0,0 +1,7 @@ + + + + Picture.svg + false + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonPictures/ЮТУпал/Ext/Picture/Picture.svg b/src/cfe/YAXUnit/CommonPictures/ЮТУпал/Ext/Picture/Picture.svg new file mode 100644 index 0000000..0334713 --- /dev/null +++ b/src/cfe/YAXUnit/CommonPictures/ЮТУпал/Ext/Picture/Picture.svg @@ -0,0 +1,6 @@ + + + + diff --git a/src/cfe/YAXUnit/CommonPictures/ЮТУспешно.xml b/src/cfe/YAXUnit/CommonPictures/ЮТУспешно.xml new file mode 100644 index 0000000..00ac380 --- /dev/null +++ b/src/cfe/YAXUnit/CommonPictures/ЮТУспешно.xml @@ -0,0 +1,17 @@ + + + + + ЮТУспешно + + + ru + Успешно + + + + false + false + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonPictures/ЮТУспешно/Ext/Picture.xml b/src/cfe/YAXUnit/CommonPictures/ЮТУспешно/Ext/Picture.xml new file mode 100644 index 0000000..0da1845 --- /dev/null +++ b/src/cfe/YAXUnit/CommonPictures/ЮТУспешно/Ext/Picture.xml @@ -0,0 +1,7 @@ + + + + Picture.svg + false + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonPictures/ЮТУспешно/Ext/Picture/Picture.svg b/src/cfe/YAXUnit/CommonPictures/ЮТУспешно/Ext/Picture/Picture.svg new file mode 100644 index 0000000..103604d --- /dev/null +++ b/src/cfe/YAXUnit/CommonPictures/ЮТУспешно/Ext/Picture/Picture.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/cfe/YAXUnit/CommonPictures/ЮТЭлементыТестов.xml b/src/cfe/YAXUnit/CommonPictures/ЮТЭлементыТестов.xml new file mode 100644 index 0000000..01e8ca5 --- /dev/null +++ b/src/cfe/YAXUnit/CommonPictures/ЮТЭлементыТестов.xml @@ -0,0 +1,17 @@ + + + + + ЮТЭлементыТестов + + + ru + Элементы тестов + + + + false + false + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonPictures/ЮТЭлементыТестов/Ext/Picture.xml b/src/cfe/YAXUnit/CommonPictures/ЮТЭлементыТестов/Ext/Picture.xml new file mode 100644 index 0000000..0da1845 --- /dev/null +++ b/src/cfe/YAXUnit/CommonPictures/ЮТЭлементыТестов/Ext/Picture.xml @@ -0,0 +1,7 @@ + + + + Picture.svg + false + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonPictures/ЮТЭлементыТестов/Ext/Picture/Picture.svg b/src/cfe/YAXUnit/CommonPictures/ЮТЭлементыТестов/Ext/Picture/Picture.svg new file mode 100644 index 0000000..ac31420 --- /dev/null +++ b/src/cfe/YAXUnit/CommonPictures/ЮТЭлементыТестов/Ext/Picture/Picture.svg @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + diff --git a/src/cfe/YAXUnit/CommonTemplates/ЮТRegEx1CAddin.xml b/src/cfe/YAXUnit/CommonTemplates/ЮТRegEx1CAddin.xml new file mode 100644 index 0000000..0f7f46e --- /dev/null +++ b/src/cfe/YAXUnit/CommonTemplates/ЮТRegEx1CAddin.xml @@ -0,0 +1,16 @@ + + + + + ЮТRegEx1CAddin + + + ru + Reg ex1 c addin + + + + AddIn + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonTemplates/ЮТRegEx1CAddin/Ext/Template.bin b/src/cfe/YAXUnit/CommonTemplates/ЮТRegEx1CAddin/Ext/Template.bin new file mode 100644 index 0000000000000000000000000000000000000000..3e59669eb443e7498b6a2b509513f4d4d8ba2f00 GIT binary patch literal 528812 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%0DQy2<>r?L89LiI}5N_1aXMI>^@NhY1OC!7Q! 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

W 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

qq-& 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 ?q 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

_Vp0`OX^YF3k3hlo-Uiifl(i2S3HT$9~ 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 TOM6$;J7z&qykz@<$fMWCwml#%|AB8 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¨L;=o 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 + + + + ЮТYaxUnitAddIn + + + ru + ЮТYax unit add in + + + + AddIn + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonTemplates/ЮТYaxUnitAddIn/Ext/Template.bin b/src/cfe/YAXUnit/CommonTemplates/ЮТYaxUnitAddIn/Ext/Template.bin new file mode 100644 index 0000000000000000000000000000000000000000..c651293746d866d70d4534a196a00bf708cb7ae6 GIT binary patch literal 106819 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%0D+0tvEOmtW)NkOK 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 Z_+NOViaadbKRv;G#P^RBkoV6#{|6! + + + + ЮТ_СловарьПодражателя_Компании_Наименования_ru + + + ru + Подражатель компании наименования ru + + + + TextDocument + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonTemplates/ЮТ_СловарьПодражателя_Компании_Наименования_ru/Ext/Template.txt b/src/cfe/YAXUnit/CommonTemplates/ЮТ_СловарьПодражателя_Компании_Наименования_ru/Ext/Template.txt new file mode 100644 index 0000000..304d468 --- /dev/null +++ b/src/cfe/YAXUnit/CommonTemplates/ЮТ_СловарьПодражателя_Компании_Наименования_ru/Ext/Template.txt @@ -0,0 +1,33 @@ +Рога и Копыта +Ромашка +Организатория +Содружество +Синергия +УспехПартнер +Стратегия+ +Эволюция +ОргаLife +МастерОрг +ЛидерОрг +УспехОрг +Профессиональное Организованное Решение +Стратегическая Организация +Идеальная Организация +МастерПлан +Гений в Деталях +Успешная Система +Органайзер +Профессиональная Структура +Успешное будущее +Мастера организации +Профессиональные архитекторы +Организационный гений +АльпаБанк +ВТП +Пенькофф +Сперпанк +Азито +Ямтекс +Почта Рус Лимитед +Телепам +Система успеха \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonTemplates/ЮТ_СловарьПодражателя_Компании_ПрефиксыНаименований_ru.xml b/src/cfe/YAXUnit/CommonTemplates/ЮТ_СловарьПодражателя_Компании_ПрефиксыНаименований_ru.xml new file mode 100644 index 0000000..f3587c5 --- /dev/null +++ b/src/cfe/YAXUnit/CommonTemplates/ЮТ_СловарьПодражателя_Компании_ПрефиксыНаименований_ru.xml @@ -0,0 +1,16 @@ + + + + + ЮТ_СловарьПодражателя_Компании_ПрефиксыНаименований_ru + + + ru + Подражатель компании префиксы ru + + + + TextDocument + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonTemplates/ЮТ_СловарьПодражателя_Компании_ПрефиксыНаименований_ru/Ext/Template.txt b/src/cfe/YAXUnit/CommonTemplates/ЮТ_СловарьПодражателя_Компании_ПрефиксыНаименований_ru/Ext/Template.txt new file mode 100644 index 0000000..f636297 --- /dev/null +++ b/src/cfe/YAXUnit/CommonTemplates/ЮТ_СловарьПодражателя_Компании_ПрефиксыНаименований_ru/Ext/Template.txt @@ -0,0 +1,12 @@ +AO +ГУП +ЗАО +ИП +МУП +НКО +ОП +ООО +ОАО +ПАО +ТСЖ +ФГУП \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonTemplates/ЮТ_СловарьПодражателя_Люди_ЖенскиеИмена_ru.xml b/src/cfe/YAXUnit/CommonTemplates/ЮТ_СловарьПодражателя_Люди_ЖенскиеИмена_ru.xml new file mode 100644 index 0000000..216eb83 --- /dev/null +++ b/src/cfe/YAXUnit/CommonTemplates/ЮТ_СловарьПодражателя_Люди_ЖенскиеИмена_ru.xml @@ -0,0 +1,16 @@ + + + + + ЮТ_СловарьПодражателя_Люди_ЖенскиеИмена_ru + + + ru + Подражатель люди женские имена ru + + + + TextDocument + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonTemplates/ЮТ_СловарьПодражателя_Люди_ЖенскиеИмена_ru/Ext/Template.txt b/src/cfe/YAXUnit/CommonTemplates/ЮТ_СловарьПодражателя_Люди_ЖенскиеИмена_ru/Ext/Template.txt new file mode 100644 index 0000000..4d57c68 --- /dev/null +++ b/src/cfe/YAXUnit/CommonTemplates/ЮТ_СловарьПодражателя_Люди_ЖенскиеИмена_ru/Ext/Template.txt @@ -0,0 +1,80 @@ +Агата +Агафья +Акулина +Алевтина +Александра +Алина +Алла +Анастасия +Ангелина +Анжела +Анжелика +Анна +Антонина +Валентина +Валерия +Варвара +Василиса +Вера +Вероника +Виктория +Галина +Глафира +Дарья +Евгения +Евдокия +Евпраксия +Евфросиния +Екатерина +Елена +Елизавета +Жанна +Зинаида +Зоя +Иванна +Ираида +Ирина +Ия +Кира +Клавдия +Ксения +Лариса +Лидия +Лора +Лукия +Любовь +Людмила +Майя +Маргарита +Марина +Мария +Марфа +Милица +Надежда +Наина +Наталья +Нина +Нинель +Нонна +Оксана +Октябрина +Олимпиада +Ольга +Пелагея +Полина +Прасковья +Раиса +Регина +Светлана +Синклитикия +София +Таисия +Тамара +Татьяна +Ульяна +Фаина +Феврония +Фёкла +Элеонора +Эмилия +Юлия \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonTemplates/ЮТ_СловарьПодражателя_Люди_ЖенскиеОтчества_ru.xml b/src/cfe/YAXUnit/CommonTemplates/ЮТ_СловарьПодражателя_Люди_ЖенскиеОтчества_ru.xml new file mode 100644 index 0000000..1f5b4ec --- /dev/null +++ b/src/cfe/YAXUnit/CommonTemplates/ЮТ_СловарьПодражателя_Люди_ЖенскиеОтчества_ru.xml @@ -0,0 +1,16 @@ + + + + + ЮТ_СловарьПодражателя_Люди_ЖенскиеОтчества_ru + + + ru + Подражатель люди женские отчества ru + + + + TextDocument + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonTemplates/ЮТ_СловарьПодражателя_Люди_ЖенскиеОтчества_ru/Ext/Template.txt b/src/cfe/YAXUnit/CommonTemplates/ЮТ_СловарьПодражателя_Люди_ЖенскиеОтчества_ru/Ext/Template.txt new file mode 100644 index 0000000..83f6a58 --- /dev/null +++ b/src/cfe/YAXUnit/CommonTemplates/ЮТ_СловарьПодражателя_Люди_ЖенскиеОтчества_ru/Ext/Template.txt @@ -0,0 +1,79 @@ +Александровна +Андреевна +Архиповна +Алексеевна +Антоновна +Аскольдовна +Альбертовна +Аркадьевна +Афанасьевна +Анатольевна +Артемовна +Богдановна +Болеславовна +Борисовна +Вадимовна +Васильевна +Владимировна +Валентиновна +Вениаминовна +Владиславовна +Валериевна +Викторовна +Вячеславовна +Геннадиевна +Георгиевна +Геннадьевна +Григорьевна +Даниловна +Дмитриевна +Евгеньевна +Егоровна +Ефимовна +Ждановна +Захаровна +Ивановна +Игоревна +Ильинична +Кирилловна +Кузьминична +Константиновна +Леонидовна +Леоновна +Львовна +Макаровна +Матвеевна +Михайловна +Максимовна +Мироновна +Натановна +Никифоровна +Ниловна +Наумовна +Николаевна +Олеговна +Оскаровна +Павловна +Петровна +Робертовна +Рубеновна +Руслановна +Романовна +Рудольфовна +Святославовна +Сергеевна +Степановна +Семеновна +Станиславовна +Тарасовна +Тимофеевна +Тимуровна +Федоровна +Феликсовна +Филипповна +Харитоновна +Эдуардовна +Эльдаровна +Юльевна +Юрьевна +Яковлевна diff --git a/src/cfe/YAXUnit/CommonTemplates/ЮТ_СловарьПодражателя_Люди_ЖенскиеФамилии_ru.xml b/src/cfe/YAXUnit/CommonTemplates/ЮТ_СловарьПодражателя_Люди_ЖенскиеФамилии_ru.xml new file mode 100644 index 0000000..3589872 --- /dev/null +++ b/src/cfe/YAXUnit/CommonTemplates/ЮТ_СловарьПодражателя_Люди_ЖенскиеФамилии_ru.xml @@ -0,0 +1,16 @@ + + + + + ЮТ_СловарьПодражателя_Люди_ЖенскиеФамилии_ru + + + ru + Подражатель люди женские фамилии ru + + + + TextDocument + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonTemplates/ЮТ_СловарьПодражателя_Люди_ЖенскиеФамилии_ru/Ext/Template.txt b/src/cfe/YAXUnit/CommonTemplates/ЮТ_СловарьПодражателя_Люди_ЖенскиеФамилии_ru/Ext/Template.txt new file mode 100644 index 0000000..75c5f87 --- /dev/null +++ b/src/cfe/YAXUnit/CommonTemplates/ЮТ_СловарьПодражателя_Люди_ЖенскиеФамилии_ru/Ext/Template.txt @@ -0,0 +1,250 @@ +Смирнова +Иванова +Кузнецова +Попова +Соколова +Лебедева +Козлова +Новикова +Морозова +Петрова +Волкова +Соловьева +Васильева +Зайцева +Павлова +Семенова +Голубева +Виноградова +Богданова +Воробьева +Федорова +Михайлова +Беляева +Тарасова +Белова +Комарова +Орлова +Киселева +Макарова +Андреева +Ковалева +Ильина +Гусева +Титова +Кузьмина +Кудрявцева +Баранова +Куликова +Алексеева +Степанова +Яковлева +Сорокина +Сергеева +Романова +Захарова +Борисова +Королева +Герасимова +Пономарева +Григорьева +Лазарева +Медведева +Ершова +Никитина +Соболева +Рябова +Полякова +Цветкова +Данилова +Жукова +Фролова +Журавлева +Николаева +Крылова +Максимова +Сидорова +Осипова +Белоусова +Федотова +Дорофеева +Егорова +Матвеева +Боброва +Дмитриева +Калинина +Анисимова +Петухова +Антонова +Тимофеева +Никифорова +Веселова +Филиппова +Маркова +Большакова +Суханова +Миронова +Ширяева +Александрова +Коновалова +Шестакова +Казакова +Ефимова +Денисова +Громова +Фомина +Давыдова +Мельникова +Щербакова +Блинова +Колесникова +Карпова +Афанасьева +Власова +Маслова +Исакова +Тихонова +Аксенова +Гаврилова +Родионова +Котова +Горбунова +Кудряшова +Быкова +Зуева +Третьякова +Савельева +Панова +Рыбакова +Суворова +Абрамова +Воронова +Мухина +Архипова +Трофимова +Мартынова +Емельянова +Горшкова +Чернова +Овчинникова +Селезнева +Панфилова +Копылова +Михеева +Галкина +Назарова +Лобанова +Лукина +Белякова +Потапова +Некрасова +Хохлова +Жданова +Наумова +Шилова +Воронцова +Ермакова +Дроздова +Игнатьева +Савина +Логинова +Сафонова +Капустина +Кириллова +Моисеева +Елисеева +Кошелева +Костина +Горбачева +Орехова +Ефремова +Исаева +Евдокимова +Калашникова +Кабанова +Носкова +Юдина +Кулагина +Лапина +Прохорова +Нестерова +Харитонова +Агафонова +Муравьева +Ларионова +Федосеева +Зимина +Пахомова +Шубина +Игнатова +Филатова +Крюкова +Рогова +Кулакова +Терентьева +Молчанова +Владимирова +Артемьева +Гурьева +Зиновьева +Гришина +Кононова +Дементьева +Ситникова +Симонова +Мишина +Фадеева +Комиссарова +Мамонтова +Носова +Гуляева +Шарова +Устинова +Вишнякова +Евсеева +Лаврентьева +Брагина +Константинова +Корнилова +Авдеева +Зыкова +Бирюкова +Шарапова +Никонова +Щукина +Дьячкова +Одинцова +Сазонова +Якушева +Красильникова +Гордеева +Самойлова +Князева +Беспалова +Уварова +Шашкова +Бобылева +Доронина +Белозерова +Рожкова +Самсонова +Мясникова +Лихачева +Бурова +Сысоева +Фомичева +Русакова +Стрелкова +Гущина +Тетерина +Колобова +Субботина +Фокина +Блохина +Селиверстова +Пестова +Кондратьева +Силина +Меркушева +Лыткина +Турова diff --git a/src/cfe/YAXUnit/CommonTemplates/ЮТ_СловарьПодражателя_Люди_МужскиеИмена_ru.xml b/src/cfe/YAXUnit/CommonTemplates/ЮТ_СловарьПодражателя_Люди_МужскиеИмена_ru.xml new file mode 100644 index 0000000..8367221 --- /dev/null +++ b/src/cfe/YAXUnit/CommonTemplates/ЮТ_СловарьПодражателя_Люди_МужскиеИмена_ru.xml @@ -0,0 +1,16 @@ + + + + + ЮТ_СловарьПодражателя_Люди_МужскиеИмена_ru + + + ru + Подражатель люди мужские имена ru + + + + TextDocument + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonTemplates/ЮТ_СловарьПодражателя_Люди_МужскиеИмена_ru/Ext/Template.txt b/src/cfe/YAXUnit/CommonTemplates/ЮТ_СловарьПодражателя_Люди_МужскиеИмена_ru/Ext/Template.txt new file mode 100644 index 0000000..e50230a --- /dev/null +++ b/src/cfe/YAXUnit/CommonTemplates/ЮТ_СловарьПодражателя_Люди_МужскиеИмена_ru/Ext/Template.txt @@ -0,0 +1,321 @@ +Август +Авдей +Аверкий +Аверьян +Авксентий +Автоном +Агап +Агафон +Аггей +Адам +Адриан +Азарий +Аким +Александр +Алексей +Амвросий +Амос +Ананий +Анатолий +Андрей +Андрон +Андроник +Аникей +Аникита +Анисим +Антип +Антонин +Аполлинарий +Аполлон +Арефий +Аристарх +Аркадий +Арсений +Артемий +Артем +Архип +Аскольд +Афанасий +Афиноген +Бажен +Богдан +Болеслав +Борис +Борислав +Боян +Бронислав +Будимир +Вадим +Валентин +Валерий +Валерьян +Варлаам +Варфоломей +Василий +Вацлав +Велимир +Венедикт +Вениамин +Викентий +Виктор +Викторин +Виссарион +Виталий +Владилен +Владлен +Владимир +Владислав +Влас +Всеволод +Всемил +Всеслав +Вышеслав +Вячеслав +Гаврила +Галактион +Гедеон +Геннадий +Георгий +Герасим +Герман +Глеб +Гордей +Гостомысл +Гремислав +Григорий +Гурий +Давыд +Данила +Дементий +Демид +Демьян +Денис +Дмитрий +Добромысл +Доброслав +Дорофей +Евгений +Евграф +Евдоким +Евлампий +Евсей +Евстафий +Евстигней +Егор +Елизар +Елисей +Емельян +Епифан +Еремей +Ермил +Ермолай +Ерофей +Ефим +Ефрем +Захар +Зиновий +Зосима +Иван +Игнатий +Игорь +Измаил +Изот +Изяслав +Иларион +Илья +Иннокентий +Иосиф +Ипат +Ипатий +Ипполит +Ираклий +Исай +Исидор +Казимир +Каллистрат +Капитон +Карл +Карп +Касьян +Ким +Кир +Кирилл +Клавдий +Климент +Кондрат +Кондратий +Конон +Константин +Корнил +Кузьма +Куприян +Лавр +Лаврентий +Ладимир +Ладислав +Лазарь +Лев +Леон +Леонид +Леонтий +Лонгин +Лука +Лукьян +Лучезар +Любим +Любомир +Любосмысл +Макар +Максим +Максимильян +Мариан +Марк +Мартын +Мартьян +Матвей +Мефодий +Мечислав +Милан +Милен +Милий +Милован +Мина +Мир +Мирон +Мирослав +Митофан +Михаил +Михей +Модест +Моисей +Мокей +Мстислав +Назар +Наркис +Натан +Наум +Нестор +Никандр +Никанор +Никита +Никифор +Никодим +Николай +Никон +Нифонт +Олег +Олимпий +Онуфрий +Орест +Осип +Остап +Остромир +Павел +Панкратий +Панкрат +Пантелеймон +Панфил +Парамон +Парфен +Пахом +Петр +Пимен +Платон +Поликарп +Порфирий +Потап +Пров +Прокл +Прокофий +Прохор +Радим +Радислав +Радован +Ратибор +Ратмир +Родион +Роман +Ростислав +Рубен +Руслан +Рюрик +Савва +Савватий +Савелий +Самсон +Самуил +Светозар +Святополк +Святослав +Севастьян +Селиван +Селиверст +Семен +Серафим +Сергей +Сигизмунд +Сидор +Сила +Силантий +Сильвестр +Симон +Сократ +Соломон +Софон +Софрон +Спартак +Спиридон +Станимир +Станислав +Степан +Стоян +Тарас +Твердислав +Творимир +Терентий +Тимофей +Тимур +Тит +Тихон +Трифон +Трофим +Ульян +Устин +Фадей +Федор +Федосий +Федот +Феликс +Феоктист +Феофан +Ферапонт +Филарет +Филимон +Филипп +Фирс +Флорентин +Фока +Фома +Фортунат +Фотий +Фрол +Харитон +Харлампий +Христофор +Чеслав +Эдуард +Эммануил +Эмиль +Эраст +Эрнест +Эрнст +Ювеналий +Юлиан +Юлий +Юрий +Яков +Ян +Якуб +Януарий +Ярополк +Ярослав diff --git a/src/cfe/YAXUnit/CommonTemplates/ЮТ_СловарьПодражателя_Люди_МужскиеОтчества_ru.xml b/src/cfe/YAXUnit/CommonTemplates/ЮТ_СловарьПодражателя_Люди_МужскиеОтчества_ru.xml new file mode 100644 index 0000000..c6ebae6 --- /dev/null +++ b/src/cfe/YAXUnit/CommonTemplates/ЮТ_СловарьПодражателя_Люди_МужскиеОтчества_ru.xml @@ -0,0 +1,16 @@ + + + + + ЮТ_СловарьПодражателя_Люди_МужскиеОтчества_ru + + + ru + Подражатель люди мужские отчества ru + + + + TextDocument + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonTemplates/ЮТ_СловарьПодражателя_Люди_МужскиеОтчества_ru/Ext/Template.txt b/src/cfe/YAXUnit/CommonTemplates/ЮТ_СловарьПодражателя_Люди_МужскиеОтчества_ru/Ext/Template.txt new file mode 100644 index 0000000..f06f757 --- /dev/null +++ b/src/cfe/YAXUnit/CommonTemplates/ЮТ_СловарьПодражателя_Люди_МужскиеОтчества_ru/Ext/Template.txt @@ -0,0 +1,132 @@ +Ааронович +Абрамович +Августович +Авдеевич +Аверьянович +Адамович +Адрианович +Аксёнович +Александрович +Алексеевич +Анатольевич +Андреевич +Анисимович +Антипович +Антонович +Ануфриевич +Арсенович +Арсеньевич +Артёмович +Артемьевич +Артурович +Архипович +Афанасьевич +Бенедиктович +Богданович +Бориславович +Борисович +Брониславович +Валентинович +Валерианович +Валерьевич +Валерьянович +Васильевич +Венедиктович +Викентьевич +Викторович +Виленович +Вилорович +Витальевич +Владиленович +Владиславович +Владленович +Власович +Всеволодович +Вячеславович +Гавриилович +Гаврилович +Геннадиевич +Георгиевич +Герасимович +Германович +Гертрудович +Глебович +Гордеевич +Григорьевич +Гурьевич +Давидович +Давыдович +Даниилович +Данилович +Демидович +Демьянович +Денисович +Димитриевич +Дмитриевич +Дорофеевич +Евсеевич +Евстигнеевич +Егорович +Елизарович +Елисеевич +Еремеевич +Ермилович +Ермолаевич +Ерофеевич +Ефимович +Ефимьевич +Ефремович +Ефстафьевич +Жанович +Жоресович +Захарьевич +Зиновьевич +Игнатович +Игнатьевич +Игоревич +Измаилович +Изотович +Иларионович +Ильич +Ильясович +Иосипович +Иосифович +Исидорович +Марсович +Матвеевич +Тарасович +Теймуразович +Терентьевич +Тимурович +Тихонович +Трифонович +Трофимович +Устинович +Фадеевич +Фёдорович +Федосеевич +Федосьевич +Федотович +Феликсович +Феодосьевич +Феоктистович +Феофанович +Филатович +Филимонович +Филиппович +Фокич +Фомич +Фролович +Харитонович +Харламович +Харлампович +Харлампьевич +Чеславович +Эдгардович +Эдгарович +Эдуардович +Юлианович +Юльевич +Яковлевич +Якубович +Ярославович diff --git a/src/cfe/YAXUnit/CommonTemplates/ЮТ_СловарьПодражателя_Люди_МужскиеФамилии_ru.xml b/src/cfe/YAXUnit/CommonTemplates/ЮТ_СловарьПодражателя_Люди_МужскиеФамилии_ru.xml new file mode 100644 index 0000000..292acce --- /dev/null +++ b/src/cfe/YAXUnit/CommonTemplates/ЮТ_СловарьПодражателя_Люди_МужскиеФамилии_ru.xml @@ -0,0 +1,16 @@ + + + + + ЮТ_СловарьПодражателя_Люди_МужскиеФамилии_ru + + + ru + Подражатель люди мужские фамилии ru + + + + TextDocument + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonTemplates/ЮТ_СловарьПодражателя_Люди_МужскиеФамилии_ru/Ext/Template.txt b/src/cfe/YAXUnit/CommonTemplates/ЮТ_СловарьПодражателя_Люди_МужскиеФамилии_ru/Ext/Template.txt new file mode 100644 index 0000000..db20d2e --- /dev/null +++ b/src/cfe/YAXUnit/CommonTemplates/ЮТ_СловарьПодражателя_Люди_МужскиеФамилии_ru/Ext/Template.txt @@ -0,0 +1,250 @@ +Смирнов +Иванов +Кузнецов +Попов +Соколов +Лебедев +Козлов +Новиков +Морозов +Петров +Волков +Соловьев +Васильев +Зайцев +Павлов +Семенов +Голубев +Виноградов +Богданов +Воробьев +Федоров +Михайлов +Беляев +Тарасов +Белов +Комаров +Орлов +Киселев +Макаров +Андреев +Ковалев +Ильин +Гусев +Титов +Кузьмин +Кудрявцев +Баранов +Куликов +Алексеев +Степанов +Яковлев +Сорокин +Сергеев +Романов +Захаров +Борисов +Королев +Герасимов +Пономарев +Григорьев +Лазарев +Медведев +Ершов +Никитин +Соболев +Рябов +Поляков +Цветков +Данилов +Жуков +Фролов +Журавлев +Николаев +Крылов +Максимов +Сидоров +Осипов +Белоусов +Федотов +Дорофеев +Егоров +Матвеев +Бобров +Дмитриев +Калинин +Анисимов +Петухов +Антонов +Тимофеев +Никифоров +Веселов +Филиппов +Марков +Большаков +Суханов +Миронов +Ширяев +Александров +Коновалов +Шестаков +Казаков +Ефимов +Денисов +Громов +Фомин +Давыдов +Мельников +Щербаков +Блинов +Колесников +Карпов +Афанасьев +Власов +Маслов +Исаков +Тихонов +Аксенов +Гаврилов +Родионов +Котов +Горбунов +Кудряшов +Быков +Зуев +Третьяков +Савельев +Панов +Рыбаков +Суворов +Абрамов +Воронов +Мухин +Архипов +Трофимов +Мартынов +Емельянов +Горшков +Чернов +Овчинников +Селезнев +Панфилов +Копылов +Михеев +Галкин +Назаров +Лобанов +Лукин +Беляков +Потапов +Некрасов +Хохлов +Жданов +Наумов +Шилов +Воронцов +Ермаков +Дроздов +Игнатьев +Савин +Логинов +Сафонов +Капустин +Кириллов +Моисеев +Елисеев +Кошелев +Костин +Горбачев +Орехов +Ефремов +Исаев +Евдокимов +Калашников +Кабанов +Носков +Юдин +Кулагин +Лапин +Прохоров +Нестеров +Харитонов +Агафонов +Муравьев +Ларионов +Федосеев +Зимин +Пахомов +Шубин +Игнатов +Филатов +Крюков +Рогов +Кулаков +Терентьев +Молчанов +Владимиров +Артемьев +Гурьев +Зиновьев +Гришин +Кононов +Дементьев +Ситников +Симонов +Мишин +Фадеев +Комиссаров +Мамонтов +Носов +Гуляев +Шаров +Устинов +Вишняков +Евсеев +Лаврентьев +Брагин +Константинов +Корнилов +Авдеев +Зыков +Бирюков +Шарапов +Никонов +Щукин +Дьячков +Одинцов +Сазонов +Якушев +Красильников +Гордеев +Самойлов +Князев +Беспалов +Уваров +Шашков +Бобылев +Доронин +Белозеров +Рожков +Самсонов +Мясников +Лихачев +Буров +Сысоев +Фомичев +Русаков +Стрелков +Гущин +Тетерин +Колобов +Субботин +Фокин +Блохин +Селиверстов +Пестов +Кондратьев +Силин +Меркушев +Лыткин +Туров diff --git a/src/cfe/YAXUnit/CommonTemplates/ЮТИнформацияОбОшибке.xml b/src/cfe/YAXUnit/CommonTemplates/ЮТИнформацияОбОшибке.xml new file mode 100644 index 0000000..c7a3088 --- /dev/null +++ b/src/cfe/YAXUnit/CommonTemplates/ЮТИнформацияОбОшибке.xml @@ -0,0 +1,16 @@ + + + + + ЮТИнформацияОбОшибке + + + ru + Информация об ошибке + + + + TextDocument + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonTemplates/ЮТИнформацияОбОшибке/Ext/Template.txt b/src/cfe/YAXUnit/CommonTemplates/ЮТИнформацияОбОшибке/Ext/Template.txt new file mode 100644 index 0000000..579fb28 --- /dev/null +++ b/src/cfe/YAXUnit/CommonTemplates/ЮТИнформацияОбОшибке/Ext/Template.txt @@ -0,0 +1,167 @@ + + + + + + + + TREE_CONTENT + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonTemplates/ЮТОписаниеМетаданных.xml b/src/cfe/YAXUnit/CommonTemplates/ЮТОписаниеМетаданных.xml new file mode 100644 index 0000000..7c2cb72 --- /dev/null +++ b/src/cfe/YAXUnit/CommonTemplates/ЮТОписаниеМетаданных.xml @@ -0,0 +1,16 @@ + + + + + ЮТОписаниеМетаданных + + + ru + Описание метаданных + + + + TextDocument + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/CommonTemplates/ЮТОписаниеМетаданных/Ext/Template.txt b/src/cfe/YAXUnit/CommonTemplates/ЮТОписаниеМетаданных/Ext/Template.txt new file mode 100644 index 0000000..794facb --- /dev/null +++ b/src/cfe/YAXUnit/CommonTemplates/ЮТОписаниеМетаданных/Ext/Template.txt @@ -0,0 +1,34 @@ +# Описание свойств метаданных + +| Имя | ИмяКоллекции | Конструктор | Группы | Ссылочный | Реквизиты | Измерения | Ресурсы | РеквизитыАдресации | ТабличныеЧасти | СтандартныеРеквизиты | +|----------------------------|-----------------------------|-----------------------|--------|-----------|-----------|-----------|---------|--------------------|----------------|----------------------| +| Справочник | Справочники | СоздатьЭлемент | + | + | + | | | | + | + | +| Документ | Документы | СоздатьДокумент | | + | + | | | | + | + | +| ПланВидовХарактеристик | ПланыВидовХарактеристик | СоздатьЭлемент | + | + | + | | | | + | + | +| ПланСчетов | ПланыСчетов | СоздатьСчет | | + | + | | | | + | + | +| ПланВидовРасчета | ПланыВидовРасчета | СоздатьВидРасчета | | + | + | | | | + | + | +| ПланОбмена | ПланыОбмена | СоздатьУзел | | + | + | | | | + | + | +| РегистрСведений | РегистрыСведений | СоздатьНаборЗаписей | | | + | + | + | | | + | +| РегистрНакопления | РегистрыНакопления | | | | + | + | + | | | + | +| РегистрБухгалтерии | РегистрыБухгалтерии | | | | + | + | + | | | + | +| РегистрРасчета | РегистрыРасчета | | | | + | + | + | | | + | +| БизнесПроцесс | БизнесПроцессы | СоздатьБизнесПроцесс | | + | + | | | | + | + | +| Задача | Задачи | СоздатьЗадачу | | + | + | | | + | + | + | +| Перечисление | Перечисления | | | + | | | | | | + | +| Отчет | Отчеты | | | | + | | | | + | | +| Обработка | Обработки | | | | + | | | | + | | +| Catalog | Catalogs | СоздатьЭлемент | + | + | + | | | | + | + | +| Document | Documents | СоздатьДокумент | | + | + | | | | + | + | +| ChartOfCharacteristicTypes | ChartsOfCharacteristicTypes | СоздатьЭлемент | + | + | + | | | | + | + | +| ChartOfAccounts | ChartsOfAccounts | СоздатьСчет | | + | + | | | | + | + | +| ChartOfCalculationTypes | ChartsOfCalculationTypes | СоздатьВидРасчета | | + | + | | | | + | + | +| ExchangePlan | ExchangePlans | СоздатьУзел | | + | + | | | | + | + | +| InformationRegister | InformationRegisters | СоздатьНаборЗаписей | | | + | + | + | | | + | +| AccumulationRegister | AccumulationRegisters | | | | + | + | + | | | + | +| AccountingRegister | AccountingRegisters | | | | + | + | + | | | + | +| CalculationRegister | CalculationRegisters | | | | + | + | + | | | + | +| BusinessProcess | BusinessProcesses | СоздатьБизнесПроцесс | | + | + | | | | + | + | +| Task | Tasks | СоздатьЗадачу | | + | + | | | + | + | + | +| Enum | Enums | | | + | | | | | | + | +| Report | Reports | | | | + | | | | + | | +| DataProcessor | DataProcessors | | | | + | | | | + | | diff --git a/src/cfe/YAXUnit/Configuration.xml b/src/cfe/YAXUnit/Configuration.xml new file mode 100644 index 0000000..e8d4418 --- /dev/null +++ b/src/cfe/YAXUnit/Configuration.xml @@ -0,0 +1,172 @@ + + + + + + 9cd510cd-abfc-11d4-9434-004095e12fc7 + 7aac7ebc-1c41-419f-aac1-52a9be0908ba + + + 9fcd25a0-4822-11d4-9414-008048da11f9 + a0ea5602-5711-43f0-ae72-26204f907950 + + + e3687481-0a87-462c-a166-9f34594f9bba + b8f84992-e90b-41b5-b663-77dbeb5a8c9b + + + 9de14907-ec23-4a07-96f0-85521cb6b53b + 4fb22a5b-2d3a-445e-b9c7-b51a4e59f82a + + + 51f2d5d8-ea4d-4064-8892-82951750031e + d26a61dd-a7a6-44b9-b131-be84fcf8c021 + + + e68182ea-4237-4383-967f-90c1e3370bc7 + 8339b2da-95e3-48c0-b355-f1f6179cebb2 + + + fb282519-d103-4dd3-bc12-cb271d631dfc + 7e0583a8-49fb-447b-9c04-741038e0b528 + + + + Adopted + YAXUNIT + + + ru + YAxUnit + + + + AddOn + true + ЮТ + Version8_3_10 + Russian + + 24.03 + + + + + + + + Русский + ЮТДвижок + ЮТДинамическиПодключаемые + ЮТПубличный + ЮТЗапустить + ЮТНеизвестный + ЮТОшибка + ЮТПерезапуститьУпавшие + ЮТПодсистема + ЮТПропущен + ЮТСравнить + ЮТУпал + ЮТУспешно + ЮТЭлементыТестов + ЮТ_СловарьПодражателя_Компании_Наименования_ru + ЮТ_СловарьПодражателя_Компании_ПрефиксыНаименований_ru + ЮТ_СловарьПодражателя_Люди_ЖенскиеИмена_ru + ЮТ_СловарьПодражателя_Люди_ЖенскиеОтчества_ru + ЮТ_СловарьПодражателя_Люди_ЖенскиеФамилии_ru + ЮТ_СловарьПодражателя_Люди_МужскиеИмена_ru + ЮТ_СловарьПодражателя_Люди_МужскиеОтчества_ru + ЮТ_СловарьПодражателя_Люди_МужскиеФамилии_ru + ЮТRegEx1CAddin + ЮТYaxUnitAddIn + ЮТИнформацияОбОшибке + ЮТОписаниеМетаданных + Мокито + МокитоОбучение + МокитоПерехват + МокитоПроверки + МокитоСлужебный + ЮТАсинхроннаяОбработкаСлужебныйКлиент + ЮТест + ЮТЗапросы + ЮТЗапросыСлужебныйВызовСервера + ЮТЗапросыСлужебныйКлиентСервер + ЮТИсключения + ЮТИсполнительСлужебныйВызовСервера + ЮТИсполнительСлужебныйГлобальный + ЮТИсполнительСлужебныйКлиент + ЮТИсполнительСлужебныйКлиентСервер + ЮТКоллекции + ЮТКомпоненты + ЮТКомпонентыСлужебныйВызовСервера + ЮТКомпонентыСлужебныйКлиент + ЮТКонструкторВариантов + ЮТКонструкторТестовыхДанныхСлужебный + ЮТКонтекстСлужебный + ЮТКонтекстСлужебныйВызовСервера + ЮТКонтекстСлужебныйКлиент + ЮТКонтекстТеста + ЮТЛогирование + ЮТЛогированиеСлужебный + ЮТЛогированиеСлужебныйВызовСервера + ЮТЛогИсполненияТестаСлужебный + ЮТЛокальСлужебный + ЮТМетаданные + ЮТМетаданныеСлужебный + ЮТМетаданныеСлужебныйВызовСервера + ЮТМетаданныеСлужебныйПовтИсп + ЮТМетодыСлужебный + ЮТНастройкиВыполнения + ЮТОбщий + ЮТОбщийСлужебныйВызовСервера + ЮТОтчетAllureСлужебный + ЮТОтчетJSONСлужебный + ЮТОтчетJUnitСлужебный + ЮТОтчетСлужебный + ЮТПараметрыЗапускаСлужебный + ЮТПодражатель + ЮТПодражатель_Банки + ЮТПодражатель_Компании + ЮТПодражатель_Люди + ЮТПодражательСлужебный + ЮТПодражательСлужебныйВызовСервера + ЮТПодражательСлужебныйПовтИсп + ЮТПредикаты + ЮТПредикатыСлужебныйКлиентСервер + ЮТПреобразованияСлужебный + ЮТПроверкиСлужебный + ЮТРасширенияСлужебный + ЮТРегистрацияОшибок + ЮТРегистрацияОшибокСлужебный + ЮТСлужебныйПовторногоИспользования + ЮТСобытияСлужебный + ЮТСообщенияСлужебный + ЮТСравнениеСлужебныйВызовСервера + ЮТСравнениеСлужебныйКлиентСервер + ЮТСтроки + ЮТТестовыеДанные + ЮТТестовыеДанныеСлужебный + ЮТТестовыеДанныеСлужебныйВызовСервера + ЮТТестовыеДанныеСлужебныйТаблицыЗначений + ЮТТесты + ЮТТестыСлужебный + ЮТТипыДанныхСлужебный + ЮТУтверждения + ЮТУтвержденияИБ + ЮТФабрика + ЮТФабрикаСлужебный + ЮТФайлы + ЮТФильтрацияСлужебный + ЮТЧитательСлужебный + ЮТЧитательСлужебныйВызовСервера + ОМ_ОбщегоНазаначенияСервер + ОМ_КоннекторHTTP + ЮТHTTPServiceRequest + ЮТHTTPСервисЗапрос + ЮТRecordSet + ЮТКонструкторОбъектаXDTO + ЮТКонструкторТестовыхДанных + ЮТЮнитТесты + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/DataProcessors/ЮТHTTPServiceRequest.xml b/src/cfe/YAXUnit/DataProcessors/ЮТHTTPServiceRequest.xml new file mode 100644 index 0000000..ff1cd7d --- /dev/null +++ b/src/cfe/YAXUnit/DataProcessors/ЮТHTTPServiceRequest.xml @@ -0,0 +1,32 @@ + + + + + + 852c0b16-4887-4def-83f9-18821d77f310 + d40cfd7c-5781-4c8f-9ec6-d59b29f9380a + + + 8710c3c0-b550-4cce-816c-3e4364c212ca + 82b2c6e6-4ea3-473c-90d5-4c2e17fa50de + + + + ЮТHTTPServiceRequest + + + ru + Мок для HTTP Service request + + + + true + + + false + + + + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/DataProcessors/ЮТHTTPServiceRequest/Ext/ObjectModule.bsl b/src/cfe/YAXUnit/DataProcessors/ЮТHTTPServiceRequest/Ext/ObjectModule.bsl new file mode 100644 index 0000000..ee4254b --- /dev/null +++ b/src/cfe/YAXUnit/DataProcessors/ЮТHTTPServiceRequest/Ext/ObjectModule.bsl @@ -0,0 +1,252 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Если Сервер Тогда + +#Область ОписаниеПеременных + +//@skip-check object-module-export-variable +Var HTTPMethod Export; +//@skip-check object-module-export-variable +Var BaseURL Export; +//@skip-check object-module-export-variable +Var Headers Export; +//@skip-check object-module-export-variable +Var RelativeURL Export; +//@skip-check object-module-export-variable +Var URLParameters Export; +//@skip-check object-module-export-variable +Var QueryOptions Export; + +Var Body; + +#КонецОбласти + +#Область ПрограммныйИнтерфейс + +// Возвращает тело как двоичные данные. +// +// Возвращаемое значение: +// ДвоичныеДанные - Тело +Function GetBodyAsBinaryData() Export + + BodyType = TypeOf(Body); + + If Body = Undefined Then + Return GetBinaryDataFromBase64String(""); + ElsIf BodyType = Type("BinaryData") Then + Return Body; + ElsIf BodyType = Type("String") Then + Return GetBinaryDataFromString(Body); + EndIf; + +EndFunction + +// Возвращает тело как поток. +// +// Возвращаемое значение: +// Поток - Тело +Function GetBodyAsStream() Export + + Return GetBodyAsBinaryData().OpenStreamForRead(); + +EndFunction + +// Возвращает тело как строку. +// +// Параметры: +// Encoding - КодировкаТекста, Строка - Кодировка +// +// Возвращаемое значение: +// Строка - Тело +Function GetBodyAsString(Encoding = Undefined) Export + + BodyType = TypeOf(Body); + + If Body = Undefined Then + Return ""; + ElsIf BodyType = Тип("BinaryData") Then + Return GetStringFromBinaryData(Body, Encoding); + ElsIf BodyType = Тип("String") Then + Return Body; + EndIf; + +EndFunction + +// Устанавливает тело как двоичные данные. +// При получении тела в другом формате происходит конвертация +// +// Параметры: +// Data - ДвоичныеДанные +// +// Возвращаемое значение: +// ОбработкаОбъект.ЮТHTTPServiceRequest - Мок +Function УстановитьТелоКакДвоичныеДанные(Data) Export + + Body = Data; + Return ThisObject; + +EndFunction + +// Устанавливает тело как строку. +// При получении тела в другом формате происходит конвертация +// +// Параметры: +// String - Строка +// +// Возвращаемое значение: +// ОбработкаОбъект.ЮТHTTPServiceRequest - Мок +Function УстановитьТелоКакСтроку(String) Export + + Body = String; + Return ThisObject; + +EndFunction + +// Устанавливает тело как строку JSON. +// Сериализует переданный объект в строку JSON и сохраняет в тело +// При получении тела в другом формате происходит конвертация +// +// Параметры: +// Data - Произвольный +// +// Возвращаемое значение: +// ОбработкаОбъект.ЮТHTTPServiceRequest - Мок +Function УстановитьТелоКакСтрокуJSON(Data) Export + + JSONWriter = Новый JSONWriter(); + JSONWriter.SetString(); + WriteJSON(JSONWriter, Data); + + Body = JSONWriter.Close(); + + Return ThisObject; + +EndFunction + +// Добавляет заголовок. +// +// Параметры: +// HeaderName - Строка +// Value - Строка +// +// Возвращаемое значение: +// ОбработкаОбъект.ЮТHTTPServiceRequest - Мок +Function ДобавитьЗаголовок(HeaderName, Value) Export + + Headers.Insert(HeaderName, Value); + Return ThisObject; + +EndFunction + +// Добавляет параметр запроса. +// +// Параметры: +// ParameterName - Строка +// Value - Строка +// +// Возвращаемое значение: +// ОбработкаОбъект.ЮТHTTPServiceRequest - Мок +Function ДобавитьПараметрЗапроса(ParameterName, Value) Export + + QueryOptions.Insert(ParameterName, Value); + Return ThisObject; + +EndFunction + +// Добавляет параметр URL. +// +// Параметры: +// ParameterName - Строка +// Value - Строка +// +// Возвращаемое значение: +// ОбработкаОбъект.ЮТHTTPServiceRequest - Мок +Function ДобавитьПараметрURL(ParameterName, Value) Export + + URLParameters.Insert(ParameterName, Value); + Return ThisObject; + +EndFunction + +// Устанавливает HTTP метод +// +// Параметры: +// Value - Строка - Имя http метода +// +// Возвращаемое значение: +// ОбработкаОбъект.ЮТHTTPServiceRequest - Мок +Function Метод(Value) Export + + HTTPMethod = Value; + Return ThisObject; + +EndFunction + +// Устанавливает базовый URL. +// +// Параметры: +// Value - Строка - базовый URL +// +// Возвращаемое значение: +// ОбработкаОбъект.ЮТHTTPServiceRequest - Мок +Function БазовыйURL(Value) Export + + BaseURL = Value; + Return ThisObject; + +EndFunction + +// Устанавливает относительный URL. +// +// Параметры: +// Value - Строка - относительный URL +// +// Возвращаемое значение: +// ОбработкаОбъект.ЮТHTTPServiceRequest - Мок +Function ОтносительныйURL(Value) Export + + RelativeURL = Value; + Return ThisObject; + +EndFunction + +#КонецОбласти + +#Область СлужебныеПроцедурыИФункции + +Процедура Initialize() + + HTTPMethod = "GET"; + BaseURL = ""; + Headers = New Map(); + RelativeURL = ""; + URLParameters = New Map(); + QueryOptions = New Map(); + +КонецПроцедуры + +#КонецОбласти + +#Область Инициализация + +Initialize(); + +#КонецОбласти + +#КонецЕсли diff --git a/src/cfe/YAXUnit/DataProcessors/ЮТHTTPСервисЗапрос.xml b/src/cfe/YAXUnit/DataProcessors/ЮТHTTPСервисЗапрос.xml new file mode 100644 index 0000000..a3e2381 --- /dev/null +++ b/src/cfe/YAXUnit/DataProcessors/ЮТHTTPСервисЗапрос.xml @@ -0,0 +1,32 @@ + + + + + + 5b53c341-183f-4aa0-b3ec-1f355d0f74f5 + 26dcab52-beab-4c30-aa64-02887735d56e + + + d0cecbc4-c89f-4ef2-ab8d-10bcfd8c514c + 50afe94b-4ccb-4a26-9a80-01121c6fef66 + + + + ЮТHTTPСервисЗапрос + + + ru + Мок для HTTPСервис запрос + + + + true + + + false + + + + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/DataProcessors/ЮТHTTPСервисЗапрос/Ext/ObjectModule.bsl b/src/cfe/YAXUnit/DataProcessors/ЮТHTTPСервисЗапрос/Ext/ObjectModule.bsl new file mode 100644 index 0000000..e0d9e1f --- /dev/null +++ b/src/cfe/YAXUnit/DataProcessors/ЮТHTTPСервисЗапрос/Ext/ObjectModule.bsl @@ -0,0 +1,252 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2023 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Если Сервер Тогда + +#Область ОписаниеПеременных + +//@skip-check object-module-export-variable +Перем HTTPМетод Экспорт; +//@skip-check object-module-export-variable +Перем БазовыйURL Экспорт; +//@skip-check object-module-export-variable +Перем Заголовки Экспорт; +//@skip-check object-module-export-variable +Перем ОтносительныйURL Экспорт; +//@skip-check object-module-export-variable +Перем ПараметрыURL Экспорт; +//@skip-check object-module-export-variable +Перем ПараметрыЗапроса Экспорт; + +Перем Тело; + +#КонецОбласти + +#Область ПрограммныйИнтерфейс + +// Возвращает тело как двоичные данные. +// +// Возвращаемое значение: +// ДвоичныеДанные - Тело +Функция ПолучитьТелоКакДвоичныеДанные() Экспорт + + ТипТела = ТипЗнч(Тело); + + Если Тело = Неопределено Тогда + Возврат ПолучитьДвоичныеДанныеИзBase64Строки(""); + ИначеЕсли ТипТела = Тип("ДвоичныеДанные") Тогда + Возврат Тело; + ИначеЕсли ТипТела = Тип("Строка") Тогда + Возврат ПолучитьДвоичныеДанныеИзСтроки(Тело); + КонецЕсли; + +КонецФункции + +// Возвращает тело как поток. +// +// Возвращаемое значение: +// Поток - Тело +Функция ПолучитьТелоКакПоток() Экспорт + + Возврат ПолучитьТелоКакДвоичныеДанные().ОткрытьПотокДляЧтения(); + +КонецФункции + +// Возвращает тело как строку. +// +// Параметры: +// Кодировка - КодировкаТекста, Строка - Кодировка +// +// Возвращаемое значение: +// Строка - Тело +Функция ПолучитьТелоКакСтроку(Кодировка = Неопределено) Экспорт + + ТипТела = ТипЗнч(Тело); + + Если Тело = Неопределено Тогда + Возврат ""; + ИначеЕсли ТипТела = Тип("ДвоичныеДанные") Тогда + Возврат ПолучитьСтрокуИзДвоичныхДанных(Тело, Кодировка); + ИначеЕсли ТипТела = Тип("Строка") Тогда + Возврат Тело; + КонецЕсли; + +КонецФункции + +// Устанавливает тело как двоичные данные. +// При получении тела в другом формате происходит конвертация +// +// Параметры: +// Данные - ДвоичныеДанные +// +// Возвращаемое значение: +// ОбработкаОбъект.ЮТHTTPСервисЗапрос - Мок +Функция УстановитьТелоКакДвоичныеДанные(Данные) Экспорт + + Тело = Данные; + Возврат ЭтотОбъект; + +КонецФункции + +// Устанавливает тело как строку. +// При получении тела в другом формате происходит конвертация +// +// Параметры: +// Строка - Строка +// +// Возвращаемое значение: +// ОбработкаОбъект.ЮТHTTPСервисЗапрос - Мок +Функция УстановитьТелоКакСтроку(Строка) Экспорт + + Тело = Строка; + Возврат ЭтотОбъект; + +КонецФункции + +// Устанавливает тело как строку JSON. +// Сериализует переданный объект в строку JSON и сохраняет в тело +// При получении тела в другом формате происходит конвертация +// +// Параметры: +// Данные - Произвольный +// +// Возвращаемое значение: +// ОбработкаОбъект.ЮТHTTPСервисЗапрос - Мок +Функция УстановитьТелоКакСтрокуJSON(Данные) Экспорт + + ЗаписьJSON = Новый ЗаписьJSON(); + ЗаписьJSON.УстановитьСтроку(); + ЗаписатьJSON(ЗаписьJSON, Данные); + + Тело = ЗаписьJSON.Закрыть(); + + Возврат ЭтотОбъект; + +КонецФункции + +// Добавляет заголовок. +// +// Параметры: +// ИмяЗаголовка - Строка +// Значение - Строка +// +// Возвращаемое значение: +// ОбработкаОбъект.ЮТHTTPСервисЗапрос - Мок +Функция ДобавитьЗаголовок(ИмяЗаголовка, Значение) Экспорт + + Заголовки.Вставить(ИмяЗаголовка, Значение); + Возврат ЭтотОбъект; + +КонецФункции + +// Добавляет параметр запроса. +// +// Параметры: +// ИмяПараметра - Строка +// Значение - Строка +// +// Возвращаемое значение: +// ОбработкаОбъект.ЮТHTTPСервисЗапрос - Мок +Функция ДобавитьПараметрЗапроса(ИмяПараметра, Значение) Экспорт + + ПараметрыЗапроса.Вставить(ИмяПараметра, Значение); + Возврат ЭтотОбъект; + +КонецФункции + +// Добавляет параметр URL. +// +// Параметры: +// ИмяПараметра - Строка +// Значение - Строка +// +// Возвращаемое значение: +// ОбработкаОбъект.ЮТHTTPСервисЗапрос - Мок +Функция ДобавитьПараметрURL(ИмяПараметра, Значение) Экспорт + + ПараметрыURL.Вставить(ИмяПараметра, Значение); + Возврат ЭтотОбъект; + +КонецФункции + +// Устанавливает HTTP метод +// +// Параметры: +// Значение - Строка - Имя http метода +// +// Возвращаемое значение: +// ОбработкаОбъект.ЮТHTTPСервисЗапрос - Мок +Функция Метод(Значение) Экспорт + + HTTPМетод = Значение; + Возврат ЭтотОбъект; + +КонецФункции + +// Устанавливает базовый URL. +// +// Параметры: +// Значение - Строка - базовый URL +// +// Возвращаемое значение: +// ОбработкаОбъект.ЮТHTTPСервисЗапрос - Мок +Функция БазовыйURL(Значение) Экспорт + + БазовыйURL = Значение; + Возврат ЭтотОбъект; + +КонецФункции + +// Устанавливает относительный URL. +// +// Параметры: +// Значение - Строка - относительный URL +// +// Возвращаемое значение: +// ОбработкаОбъект.ЮТHTTPСервисЗапрос - Мок +Функция ОтносительныйURL(Значение) Экспорт + + ОтносительныйURL = Значение; + Возврат ЭтотОбъект; + +КонецФункции + +#КонецОбласти + +#Область СлужебныеПроцедурыИФункции + +Процедура Инициализировать() + + HTTPМетод = "GET"; + БазовыйURL = ""; + Заголовки = Новый Соответствие(); + ОтносительныйURL = ""; + ПараметрыURL = Новый Соответствие(); + ПараметрыЗапроса = Новый Соответствие(); + +КонецПроцедуры + +#КонецОбласти + +#Область Инициализация + +Инициализировать(); + +#КонецОбласти + +#КонецЕсли diff --git a/src/cfe/YAXUnit/DataProcessors/ЮТRecordSet.xml b/src/cfe/YAXUnit/DataProcessors/ЮТRecordSet.xml new file mode 100644 index 0000000..6d72015 --- /dev/null +++ b/src/cfe/YAXUnit/DataProcessors/ЮТRecordSet.xml @@ -0,0 +1,217 @@ + + + + + + 40542278-a176-447b-b729-967555b6fbc5 + 5802b53d-bb23-4f8e-b96b-9ba39325447a + + + 6d7fc763-87bb-4249-8308-775667798af9 + f1dcbc92-0692-415d-a538-8c7b774610d2 + + + + ЮТRecordSet + + + ru + Record set + + + + true + + + false + + + + + + + EOF + + + ru + EOF + + + + + xs:boolean + + false + + + + false + + false + false + + + DontCheck + Items + + + Auto + Auto + + + Auto + + + + + BOF + + + ru + BOF + + + + + xs:boolean + + false + + + + false + + false + false + + + DontCheck + Items + + + Auto + Auto + + + Auto + + + + + Описание + + + ru + Описание + + + + + xs:string + + 0 + Variable + + + false + + + + false + + false + false + + + DontCheck + Items + + + Auto + Auto + + + Auto + + + + + AbsolutePosition + + + ru + Absolute position + + + + + xs:decimal + + 10 + 0 + Any + + + false + + + + false + + false + false + + + DontCheck + Items + + + Auto + Auto + + + Auto + + + + + RecordCount + + + ru + Record count + + + + + xs:decimal + + 10 + 0 + Nonnegative + + + false + + + + false + + false + false + + + DontCheck + Items + + + Auto + Auto + + + Auto + + + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/DataProcessors/ЮТRecordSet/Ext/ObjectModule.bsl b/src/cfe/YAXUnit/DataProcessors/ЮТRecordSet/Ext/ObjectModule.bsl new file mode 100644 index 0000000..b6df694 --- /dev/null +++ b/src/cfe/YAXUnit/DataProcessors/ЮТRecordSet/Ext/ObjectModule.bsl @@ -0,0 +1,187 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Если Сервер Или ТолстыйКлиентОбычноеПриложение Тогда + +#Область ОписаниеПеременных + +//@skip-check object-module-export-variable +Перем Fields Экспорт; + +Перем Данные; + +#КонецОбласти + +#Область ПрограммныйИнтерфейс + +// Добавляет запись в набор данных. Это данные, которые могут быть прочитаны через интерфейс RecordSet +// +// Параметры: +// Значение1 - Произвольный +// Значение2 - Произвольный +// Значение3 - Произвольный +// Значение4 - Произвольный +// Значение5 - Произвольный +// Значение6 - Произвольный +// Значение7 - Произвольный +// Значение8 - Произвольный +// Значение9 - Произвольный +// Значение10 - Произвольный +// +// Возвращаемое значение: +// ОбработкаОбъект.ЮТRecordSet - Эмулятор +//@skip-check method-too-many-params +Функция Добавить(Значение1, + Значение2 = Неопределено, + Значение3 = Неопределено, + Значение4 = Неопределено, + Значение5 = Неопределено, + Значение6 = Неопределено, + Значение7 = Неопределено, + Значение8 = Неопределено, + Значение9 = Неопределено, + Значение10 = Неопределено) Экспорт + + Строка = Данные.Добавить(); + + УстановитьБезопасныйРежим(Истина); + + Для Инд = 1 По Данные.Колонки.Количество() Цикл + Строка[Инд - 1] = Вычислить("Значение" + Инд); + КонецЦикла; + + УстановитьФлаги(); + + Возврат ЭтотОбъект; + +КонецФункции + +// Переход к первой строке набора +Процедура MoveFirst() Экспорт + + AbsolutePosition = 0; + УстановитьФлаги(); + +КонецПроцедуры + +// Переход к следующей строке набора +Процедура MoveNext() Экспорт + + AbsolutePosition = AbsolutePosition + 1; + УстановитьФлаги(); + +КонецПроцедуры + +// Закрытие набора и очистка данных +Процедура Close() Экспорт + + Данные = Неопределено; + УстановитьФлаги(); + ОбновитьFields(); + +КонецПроцедуры + +// Возвращает информацию о колонке набора +// +// Параметры: +// ИндексПоля - Число - Индекс колонки +// +// Возвращаемое значение: +// Структура - Fields: +// * Name - Строка - Имя колонки +// * Value - Произвольный - Значения колонки для текущей строки набора +Функция Fields(ИндексПоля) Экспорт + + Если Данные <> Неопределено И Данные.Количество() <> 0 Тогда + Значение = Данные[AbsolutePosition][ИндексПоля]; + Иначе + Значение = Неопределено + КонецЕсли; + + //@skip-check constructor-function-return-section + Возврат Новый Структура("Name, Value", Данные.Колонки[ИндексПоля].Имя, Значение); + +КонецФункции + +// Возвращает признак, что все записи набора прочитаны +// +// Возвращаемое значение: +// Булево +Функция EOF() Экспорт + + Возврат EOF; + +КонецФункции + +// Возвращает признак, который показывает, находится ли текущее положение записи курсора перед первой записью +// +// Возвращаемое значение: +// Булево +Функция BOF() Экспорт + + Возврат BOF; + +КонецФункции + +#КонецОбласти + +#Область СлужебныйПрограммныйИнтерфейс +// Инициализирует эмулятор RecordSet. Устанавливает информацию о колонках и служебные данные. +// Параметры: +// Колонки - Строка - Имена колонок, разделенные запятой +// +// Возвращаемое значение: +// ОбработкаОбъект.ЮТRecordSet - Эмулятор +Функция Инициализировать(Знач Колонки) Экспорт + + Данные = Новый ТаблицаЗначений(); + + Колонки = ЮТСтроки.РазделитьСтроку(Колонки, ","); + + Для Каждого Колонка Из Колонки Цикл + Данные.Колонки.Добавить(Колонка); + КонецЦикла; + + ОбновитьFields(); + MoveFirst(); + + Возврат ЭтотОбъект; + +КонецФункции +#КонецОбласти + +#Область СлужебныеПроцедурыИФункции + +Процедура УстановитьФлаги() + + EOF = Данные = Неопределено ИЛИ Данные.Количество() <= AbsolutePosition; + BOF = Данные = Неопределено ИЛИ Данные.Количество() = 0 ИЛИ AbsolutePosition < 0; + RecordCount = ?(Данные = Неопределено, 0, Данные.Количество()); + +КонецПроцедуры + +Процедура ОбновитьFields() + + Количество = ?(Данные = Неопределено, 0, Данные.Колонки.Количество()); + Fields = Новый Структура("Count", Количество); + +КонецПроцедуры + +#КонецОбласти + +#КонецЕсли diff --git a/src/cfe/YAXUnit/DataProcessors/ЮТКонструкторОбъектаXDTO.xml b/src/cfe/YAXUnit/DataProcessors/ЮТКонструкторОбъектаXDTO.xml new file mode 100644 index 0000000..1ddc000 --- /dev/null +++ b/src/cfe/YAXUnit/DataProcessors/ЮТКонструкторОбъектаXDTO.xml @@ -0,0 +1,32 @@ + + + + + + 4d0c09ec-ea56-4aef-852c-42a99d491406 + ac59e2e1-acef-483b-b47d-b9aa6bcde7cd + + + f43e3751-6657-41b5-a060-07b0bcd9b2c0 + 66b97e8e-5ab2-4e0b-8e10-a14a755c4e0b + + + + ЮТКонструкторОбъектаXDTO + + + ru + Конструктор объекта XDTO + + + + true + + + false + + + + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/DataProcessors/ЮТКонструкторОбъектаXDTO/Ext/ObjectModule.bsl b/src/cfe/YAXUnit/DataProcessors/ЮТКонструкторОбъектаXDTO/Ext/ObjectModule.bsl new file mode 100644 index 0000000..d89b5e0 --- /dev/null +++ b/src/cfe/YAXUnit/DataProcessors/ЮТКонструкторОбъектаXDTO/Ext/ObjectModule.bsl @@ -0,0 +1,375 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Если Сервер Или ТолстыйКлиентОбычноеПриложение Тогда + +#Область ОписаниеПеременных + +Перем ТекущийОбъект; +Перем ТекущийТип; +Перем СтекОбъектов; +Перем Фабрика; + +#КонецОбласти + +#Область ПрограммныйИнтерфейс + +// Устанавливает значение реквизита объекта. +// +// Параметры: +// ИмяРеквизита - Строка - Имя реквизита объекта +// Значение - Произвольный - Значение реквизита объекта +// +// Возвращаемое значение: +// ОбработкаОбъект.ЮТКонструкторОбъектаXDTO - Конструктор +Функция Установить(ИмяРеквизита, Значение) Экспорт + + ТекущийОбъект[ИмяРеквизита] = Значение; + + Возврат ЭтотОбъект; + +КонецФункции + +// Устанавливает значения реквизитов объекта. +// +// Параметры: +// ЗначенияРеквизитов - Структура - Устанавливаемые значения реквизитов +// +// Возвращаемое значение: +// ОбработкаОбъект.ЮТКонструкторОбъектаXDTO - Конструктор +Функция УстановитьРеквизиты(ЗначенияРеквизитов) Экспорт + + Для Каждого ЗначениеРеквизита Из ЗначенияРеквизитов Цикл + ТекущийОбъект[ЗначениеРеквизита.Ключ] = ЗначениеРеквизита.Значение; + КонецЦикла; + + Возврат ЭтотОбъект; + +КонецФункции + +// Устанавливает фиктивное значение реквизита объекта. +// +// На основании типа реквизита генерируется фиктивное значение. +// +// * Для примитивных значение генерируется случайное значение +// * Для объектных типов создается новый объект +// * Для коллекций - генерируется случайно количество случайных элементов (на основании типа) +// +// Параметры: +// ИмяРеквизита - Строка - Имя реквизита объекта +// +// Возвращаемое значение: +// ОбработкаОбъект.ЮТКонструкторОбъектаXDTO - Конструктор +Функция Фикция(ИмяРеквизита) Экспорт + + Свойство = Свойство(ИмяРеквизита); + Значение = СлучайноеЗначениеСвойства(Свойство, 0); + Установить(ИмяРеквизита, Значение); + + Возврат ЭтотОбъект; + +КонецФункции + +// Заполняет обязательные реквизиты объекта фиктивными значениями +// +// На основании типа объекта определяются обязательные поля. +// Для них генерируются и устанавливаются фиктивные значение. +// +// * Для примитивных значение генерируется случайное значение +// * Для объектных типов создается новый объект +// * Для коллекций - генерируется случайно количество случайных элементов (на основании типа) +// +// Возвращаемое значение: +// ОбработкаОбъект.ЮТКонструкторОбъектаXDTO - Конструктор +Функция ФикцияОбязательныхПолей() Экспорт + + Для Каждого Свойство Из ТекущийТип.Свойства Цикл + + Если НЕ Свойство.ВозможноПустое И НеЗаполнено(Свойство, ТекущийОбъект[Свойство.Имя]) Тогда + УстановитьСлучайноеЗначениеСвойства(ТекущийОбъект, Свойство, 0); + КонецЕсли; + + КонецЦикла; + + Возврат ЭтотОбъект; + +КонецФункции + +// Заполняет неустановленные реквизиты объекта фиктивными значениями +// +// На основании типа объекта определяются обязательные поля. +// Для них генерируются и устанавливаются фиктивные значение. +// +// * Для примитивных значение генерируется случайное значение +// * Для объектных типов создается новый объект +// * Для коллекций - генерируется случайно количество случайных элементов (на основании типа) +// +// Возвращаемое значение: +// ОбработкаОбъект.ЮТКонструкторОбъектаXDTO - Конструктор +Функция ФикцияНезаполненных() Экспорт + + Для Каждого Свойство Из ТекущийТип.Свойства Цикл + + Если НеЗаполнено(Свойство, ТекущийОбъект[Свойство.Имя]) Тогда + УстановитьСлучайноеЗначениеСвойства(ТекущийОбъект, Свойство, 0); + КонецЕсли; + + КонецЦикла; + + Возврат ЭтотОбъект; + +КонецФункции + +// Возвращает основной объект XDTO +// +// Возвращаемое значение: +// ОбъектXDTO +Функция ДанныеОбъекта() Экспорт + + Возврат СтекОбъектов[0]; + +КонецФункции + +// Добавляет новый объект в реквизит-коллекцию +// +// Параметры: +// ИмяРеквизита - Строка - Имя реквизиты коллекции +// +// Возвращаемое значение: +// ОбработкаОбъект.ЮТКонструкторОбъектаXDTO - Добавить новый +Функция ДобавитьНовый(ИмяРеквизита) Экспорт + + Свойство = Свойство(ИмяРеквизита); + + Если НЕ ЭтоТипОбъектаXDTO(Свойство.Тип) Тогда + ВызватьИсключение СтрШаблон("Метод применяется только для свойств-объектов. Реквизит: %1 имеет тип %2", ИмяРеквизита, Свойство.Тип); + КонецЕсли; + + Коллекция = ТекущийОбъект[Свойство.Имя]; + ДобавитьНовыйОбъектВСтек(Свойство.Тип); + + Коллекция.Добавить(ТекущийОбъект); + + Возврат ЭтотОбъект; + +КонецФункции + +// Переходит на уровень выше по стеку. +// +// Возвращаемое значение: +// ОбработкаОбъект.ЮТКонструкторОбъектаXDTO - Перейти к владельцу +Функция ПерейтиКВладельцу() Экспорт + + УдалитьПоследнийИзСтека(); + + Возврат ЭтотОбъект; + +КонецФункции + +#КонецОбласти + +#Область СлужебныйПрограммныйИнтерфейс + +Процедура Инициализировать(ИмяТипаОбъекта, ПространствоИмен, ФабрикаОбъектов = Неопределено) Экспорт + + Если ФабрикаОбъектов = Неопределено Тогда + Фабрика = ФабрикаXDTO; + Иначе + Фабрика = ФабрикаОбъектов; + КонецЕсли; + + СтекОбъектов = Новый Массив(); + ТипОбъекта = Фабрика.Тип(ПространствоИмен, ИмяТипаОбъекта); + ДобавитьНовыйОбъектВСтек(ТипОбъекта); + +КонецПроцедуры + +#КонецОбласти + +#Область СлужебныеПроцедурыИФункции + +Функция Свойство(ИмяСвойства) + + Свойство = ТекущийТип.Свойства.Получить(ИмяСвойства); + + Если Свойство = Неопределено Тогда + Сообщение = СтрШаблон("Тип XDTO `%1` не содержит свойства `%2`", ТекущийТип.Имя, ИмяСвойства); + ВызватьИсключение Сообщение; + КонецЕсли; + + Возврат Свойство; + +КонецФункции + +Процедура ДобавитьНовыйОбъектВСтек(Тип) + + Объект = НовыйОбъект(Тип); + СтекОбъектов.Добавить(Объект); + ТекущийОбъект = Объект; + ТекущийТип = Тип; + +КонецПроцедуры + +Процедура УдалитьПоследнийИзСтека() + + ИндексПоследнего = СтекОбъектов.ВГраница(); + + ТекущийОбъект = СтекОбъектов[ИндексПоследнего - 1]; + ТекущийТип = ТекущийОбъект.Тип(); + + СтекОбъектов.Удалить(ИндексПоследнего); + +КонецПроцедуры + +Функция СлучайноеЗначениеСвойства(Свойство, Уровень = 0) + + ТипСвойства = Свойство.Тип; + Если ТипЗнч(ТипСвойства) = Тип("ТипЗначенияXDTO") Тогда + Возврат СлучайноеЗначениеПримитипа(Свойство); + ИначеЕсли Уровень < 3 Тогда + Возврат СлучайноеЗначениеОбъекта(Свойство, Уровень + 1); + КонецЕсли; + +КонецФункции + +Функция СлучайноеЗначениеПримитипа(Свойство) + + Тип = Свойство.Тип; + + Если Тип.Имя = "string" И СтрНайти(НРег(Свойство.Имя), "uid") Тогда + Возврат ЮТест.Данные().УникальнаяСтрока(); + ИначеЕсли Тип.Имя = "string" Тогда + Возврат ЮТест.Данные().СлучайнаяСтрока(); + ИначеЕсли Тип.Имя = "boolean" Тогда + Возврат ЮТест.Данные().СлучайноеБулево(); + ИначеЕсли Тип.Имя = "integer" Тогда + Возврат ЮТест.Данные().СлучайноеЧисло(); + ИначеЕсли Тип.Имя = "decimal" Тогда + Возврат ЮТест.Данные().СлучайноеЧисло(, , 3); + ИначеЕсли Тип.Имя = "time" Тогда + Возврат ЮТест.Данные().СлучайноеВремя(); + ИначеЕсли Тип.Имя = "date" Тогда + Возврат НачалоДня(ЮТест.Данные().СлучайнаяДата()); + ИначеЕсли Тип.Имя = "dateTime" Тогда + Возврат ЮТест.Данные().СлучайнаяДата(); + ИначеЕсли Тип.БазовыйТип.Имя = "AnyRef" Тогда + Возврат ЮТест.Данные().УникальнаяСтрока(); + ИначеЕсли ЗначениеЗаполнено(Тип.Фасеты) И Тип.Фасеты[0].Вид = ВидФасетаXDTO.Перечисление Тогда + Возврат СлучайноеЗначениеПеречисления(Тип); + Иначе + ВызватьИсключение "Неподдерживаемый тип примитива XDTO: " + Тип; + КонецЕсли; + +КонецФункции + +Функция СлучайноеЗначениеОбъекта(Свойство, Уровень) + + Пакет = НовыйОбъект(Свойство.Тип); + ЗаполнитьПакетСлучайнымиЗначениями(Пакет, Уровень); + + Возврат Пакет; + +КонецФункции + +Процедура ЗаполнитьПакетСлучайнымиЗначениями(Пакет, Уровень = 0) + + Тип = Пакет.Тип(); + Для Каждого Свойство Из Тип.Свойства Цикл + + Если НеЗаполнено(Свойство, Пакет[Свойство.Имя]) Тогда + УстановитьСлучайноеЗначениеСвойства(Пакет, Свойство, Уровень); + КонецЕсли; + + КонецЦикла; + +КонецПроцедуры + +Процедура УстановитьСлучайноеЗначениеСвойства(Пакет, Свойство, Уровень) + + ЭтоСписок = ЭтоСписок(Свойство); + + Если ЭтоСписок Тогда + СписокСлучайныхЗначений(Пакет[Свойство.Имя], Свойство, Уровень); + Иначе + Пакет[Свойство.Имя] = СлучайноеЗначениеСвойства(Свойство, Уровень); + КонецЕсли; + +КонецПроцедуры + +Функция НеЗаполнено(Свойство, Значение) + + ЭтоСписок = ЭтоСписок(Свойство); + + Если ЭтоСписок И Значение.Количество() Тогда + Возврат Значение.Количество() = 0; + Иначе + Возврат НЕ ЗначениеЗаполнено(Значение); + КонецЕсли; + +КонецФункции + +Функция ЭтоСписок(Свойство) + + Возврат Свойство.ВерхняяГраница = -1 ИЛИ Свойство.ВерхняяГраница > 1; + +КонецФункции + +Процедура СписокСлучайныхЗначений(Список, Свойство, Уровень) + + Если Свойство.ВерхняяГраница = -1 Тогда + Количество = ЮТест.Данные().СлучайноеЧисло(Свойство.НижняяГраница, 10); + Иначе + Количество = ЮТест.Данные().СлучайноеЧисло(Свойство.НижняяГраница, Свойство.ВерхняяГраница); + КонецЕсли; + + Для Инд = 0 По Количество Цикл + Значение = СлучайноеЗначениеСвойства(Свойство, Уровень); + Список.Добавить(Значение); + КонецЦикла; + +КонецПроцедуры + +Функция НовыйОбъект(Тип) + + Возврат Фабрика.Создать(Тип); + +КонецФункции + +Функция ЭтоТипОбъектаXDTO(ТипСвойства) + + Возврат ТипЗнч(ТипСвойства) = Тип("ТипОбъектаXDTO"); + +КонецФункции + +Функция СлучайноеЗначениеПеречисления(Тип) + + Значения = Новый Массив(); + + Для Каждого Фасет Из Тип.Фасеты Цикл + Если Фасет.Вид = ВидФасетаXDTO.Перечисление Тогда + Значения.Добавить(Фасет.Значение); + КонецЕсли; + КонецЦикла; + + Возврат ЮТест.Данные().СлучайноеЗначениеИзСписка(Значения); + +КонецФункции + +#КонецОбласти + +#КонецЕсли diff --git a/src/cfe/YAXUnit/DataProcessors/ЮТКонструкторТестовыхДанных.xml b/src/cfe/YAXUnit/DataProcessors/ЮТКонструкторТестовыхДанных.xml new file mode 100644 index 0000000..11a191b --- /dev/null +++ b/src/cfe/YAXUnit/DataProcessors/ЮТКонструкторТестовыхДанных.xml @@ -0,0 +1,34 @@ + + + + + + feb4bd6a-59d7-4b74-98a7-c722b4300cc1 + 4a6b9b50-8e10-4172-ab37-7ec247e39f1a + + + 6c763c70-caff-423c-a7db-0024c94f60ab + 5df0b0b8-38c5-4709-b2ea-865d8e990c86 + + + + ЮТКонструкторТестовыхДанных + + + ru + Конструктор тестовых данных + + + + false + DataProcessor.ЮТКонструкторТестовыхДанных.Form.КлиентскийКонструктор + + false + + + + +
КлиентскийКонструктор
+
+
+
\ No newline at end of file diff --git a/src/cfe/YAXUnit/DataProcessors/ЮТКонструкторТестовыхДанных/Ext/ObjectModule.bsl b/src/cfe/YAXUnit/DataProcessors/ЮТКонструкторТестовыхДанных/Ext/ObjectModule.bsl new file mode 100644 index 0000000..c55ae33 --- /dev/null +++ b/src/cfe/YAXUnit/DataProcessors/ЮТКонструкторТестовыхДанных/Ext/ObjectModule.bsl @@ -0,0 +1,261 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Если Сервер Или ТолстыйКлиентОбычноеПриложение Тогда + +#Область ОписаниеПеременных + +// см. ЮТКонструкторТестовыхДанныхСлужебный.НовыйКонтекстКонструктора +Перем Контекст; + +#КонецОбласти + +#Область ПрограммныйИнтерфейс + +// Устанавливает значение реквизита создаваемого объекта. +// +// Если метод вызывается после вызова см. ТабличнаяЧасть, то устанавливается значение реквизита строки табличной части +// +// Параметры: +// ИмяРеквизита - Строка - Имя реквизита объекта или табличной части +// Значение - Произвольный - Значение реквизита объекта или табличной части +// +// Возвращаемое значение: +// ОбработкаОбъект.ЮТКонструкторТестовыхДанных - Конструктор +Функция Установить(ИмяРеквизита, Значение) Экспорт + + ЮТКонструкторТестовыхДанныхСлужебный.Установить(Контекст, ИмяРеквизита, Значение); + Возврат ЭтотОбъект; + +КонецФункции + +// Устанавливает значения реквизитов создаваемого объекта. +// +// Если метод вызывается после вызова см. ТабличнаяЧасть, то устанавливаются значения реквизитов строки табличной части +// +// Параметры: +// ЗначенияРеквизитов - Структура - Устанавливаемые значения реквизитов +// +// Возвращаемое значение: +// ОбработкаОбъект.ЮТКонструкторТестовыхДанных - Установить реквизиты +Функция УстановитьРеквизиты(ЗначенияРеквизитов) Экспорт + + ЮТКонструкторТестовыхДанныхСлужебный.УстановитьРеквизиты(Контекст, ЗначенияРеквизитов); + Возврат ЭтотОбъект; + +КонецФункции + +// Устанавливает фиктивное значение реквизита создаваемого объекта. +// +// Если метод вызывается после вызова см. ТабличнаяЧасть, то устанавливается значение реквизита строки табличной части. +// +// На основании менеджера и имени реквизита вычисляется его тип, а по типу генерируется фиктивное значение. +// +// * Для примитивных значение генерируется случайное значение +// * Для ссылочных типов создается новый объект +// * Для перечислений (в том числе системных) выбирается случайно значение перечисления +// +// Параметры: +// ИмяРеквизита - Строка - Имя реквизита объекта или табличной части +// РеквизитыЗаполнения - Структура - Значения реквизитов заполнения создаваемого объекта базы +// - Неопределено +// ОграничениеТипа - Тип, ОписаниеТипов - Испольуется для ограничения типа составного реквизита, будет сгерерировано значение указанного типа +// - Неопределено - Будет сгенерировано значение, на основании типа реквизита, если реквизит составной, то будет использован случайный тип +// +// Возвращаемое значение: +// ОбработкаОбъект.ЮТКонструкторТестовыхДанных - Конструктор +Функция Фикция(ИмяРеквизита, РеквизитыЗаполнения = Неопределено, ОграничениеТипа = Неопределено) Экспорт + + ЮТКонструкторТестовыхДанныхСлужебный.Фикция(Контекст, ИмяРеквизита, РеквизитыЗаполнения, ОграничениеТипа); + Возврат ЭтотОбъект; + +КонецФункции + +// Заполняет обязательные поля объекта фиктивными значениями +// +// Если метод вызывается после вызова см. ТабличнаяЧасть, то устанавливаются значения реквизитов строки табличной части. +// +// На основании метаданных определяются обязательные поля (Проверка заполнения = Выдавать ошибку), +// для них генерируются и устанавливаются фиктивные значение. +// +// * Для примитивных значение генерируется случайное значение +// * Для ссылочных типов создается новый объект +// * Для перечислений (в том числе системных) выбирается случайно значение перечисления +// +// Возвращаемое значение: +// ОбработкаОбъект.ЮТКонструкторТестовыхДанных - Конструктор +Функция ФикцияОбязательныхПолей() Экспорт + + ЮТКонструкторТестовыхДанныхСлужебный.ФикцияОбязательныхПолей(Контекст); + Возврат ЭтотОбъект; + +КонецФункции + +// Переключает конструктор на заполнение табличной части объекта. +// +// Параметры: +// ИмяТабличнойЧасти - Строка - Имя табличной части +// +// Возвращаемое значение: +// ОбработкаОбъект.ЮТКонструкторТестовыхДанных - Конструктор +Функция ТабличнаяЧасть(ИмяТабличнойЧасти) Экспорт + + ЮТКонструкторТестовыхДанныхСлужебный.ТабличнаяЧасть(Контекст, ИмяТабличнойЧасти); + Возврат ЭтотОбъект; + +КонецФункции + +// Переключает конструктор на заполнение объекта. +// +// Возвращаемое значение: +// ОбработкаОбъект.ЮТКонструкторТестовыхДанных - Конструктор +Функция Объект() Экспорт + + ЮТКонструкторТестовыхДанныхСлужебный.ТабличнаяЧасть(Контекст, Неопределено); + Возврат ЭтотОбъект; + +КонецФункции + +// Добавляет новую строку табличной части объекта. +// При необходимости можно выполнить установку реквизитов новой строки +// +// Параметры: +// ЗначенияРеквизитов - Структура - Устанавливаемые значения реквизитов новой строки +// +// Возвращаемое значение: +// ОбработкаОбъект.ЮТКонструкторТестовыхДанных - Конструктор +Функция ДобавитьСтроку(ЗначенияРеквизитов = Неопределено) Экспорт + + ЮТКонструкторТестовыхДанныхСлужебный.ДобавитьСтроку(Контекст, ЗначенияРеквизитов); + Возврат ЭтотОбъект; + +КонецФункции + +// Устанавливает дополнительное свойство объекта. +// +// Параметры: +// ИмяСвойства - Строка - Имя дополнительного свойства +// Значение - Произвольный - Значение дополнительного свойства +// +// Возвращаемое значение: +// ОбработкаОбъект.ЮТКонструкторТестовыхДанных - Конструктор +Функция УстановитьДополнительноеСвойство(ИмяСвойства, Значение = Неопределено) Экспорт + + ЮТКонструкторТестовыхДанныхСлужебный.УстановитьДополнительноеСвойство(Контекст, ИмяСвойства, Значение); + Возврат ЭтотОбъект; + +КонецФункции + +// Создает новый объект и возвращает его или ссылку. +// +// Важно, после создания данные не очищаются, поэтому многократный вызов метода создаст множество одинаковых объектов. +// Если вы хотите создать полностью новый объект, необходимо по-новой инициировать конструктор. +// +// Параметры: +// ВернутьОбъект - Булево - Вернуть объект вместо ссылки +// ОбменДаннымиЗагрузка - Булево - Записать объект с признаком `ОбменДанными.Загрузка = Истина` +// +// Возвращаемое значение: +// Произвольный - Созданный объект или ссылка на него +Функция Записать(ВернутьОбъект = Ложь, ОбменДаннымиЗагрузка = Ложь) Экспорт + + Возврат ЮТКонструкторТестовыхДанныхСлужебный.Записать(Контекст, ВернутьОбъект, ОбменДаннымиЗагрузка); + +КонецФункции + +// Создает новый объект. +// +// Важно, после создания данные не очищаются, поэтому многократный вызов метода создаст множество одинаковых объектов. +// Если вы хотите создать полностью новый объект, необходимо по-новой инициировать конструктор. +// +// Параметры: +// ОбменДаннымиЗагрузка - Булево - Записать объект с признаком `ОбменДанными.Загрузка = Истина` +// +// Возвращаемое значение: +// ОбработкаОбъект.ЮТКонструкторТестовыхДанных - Конструктор +Функция ДобавитьЗапись(ОбменДаннымиЗагрузка = Ложь) Экспорт + + ЮТКонструкторТестовыхДанныхСлужебный.Записать(Контекст, Ложь, ОбменДаннымиЗагрузка); + + Возврат ЭтотОбъект; + +КонецФункции + +// Создает и возвращяет новый объект (не записывая его). +// +// Важно, после создания данные не очищаются, поэтому многократный вызов метода создаст множество одинаковых объектов. +// Если вы хотите создать полностью новый объект, необходимо по-новой инициировать конструктор. +// +// Возвращаемое значение: +// Произвольный - Созданный объект. +Функция НовыйОбъект() Экспорт + + Возврат ЮТКонструкторТестовыхДанныхСлужебный.НовыйОбъект(Контекст); + +КонецФункции + +// Создает и проводит новый документ. Возвращает объект или или ссылку на него. +// +// Важно, после создания данные не очищаются, поэтому многократный вызов метода создать множество объектов. +// Если вы хотите создать полностью новый объект, необходимо по-новой инициировать конструктор. +// +// Параметры: +// ВернутьОбъект - Булево - Вернуть объект вместо ссылки +// +// Возвращаемое значение: +// Произвольный - Созданный объект или ссылка на него +Функция Провести(ВернутьОбъект = Ложь) Экспорт + + Возврат ЮТКонструкторТестовыхДанныхСлужебный.Провести(Контекст, ВернутьОбъект); + +КонецФункции + +// Возвращает данные текущей строки табличной части объекта. +// +// Возвращаемое значение: +// - Структура - Данные строки +// - Неопределено - Если заполняется объект +Функция ДанныеСтроки() Экспорт + + Возврат ЮТКонструкторТестовыхДанныхСлужебный.ДанныеСтроки(Контекст); + +КонецФункции + +// Возвращает данные создаваемого объекта. +// +// Возвращаемое значение: +// Структура - Данные объекта +Функция ДанныеОбъекта() Экспорт + + Возврат ЮТКонструкторТестовыхДанныхСлужебный.ДанныеОбъекта(Контекст); + +КонецФункции + +#КонецОбласти + +#Область СлужебныйПрограммныйИнтерфейс + +Процедура Инициализировать(Менеджер) Экспорт + + Контекст = ЮТКонструкторТестовыхДанныхСлужебный.НовыйКонтекстКонструктора(Менеджер); + +КонецПроцедуры + +#КонецОбласти + +#КонецЕсли diff --git a/src/cfe/YAXUnit/DataProcessors/ЮТКонструкторТестовыхДанных/Forms/КлиентскийКонструктор.xml b/src/cfe/YAXUnit/DataProcessors/ЮТКонструкторТестовыхДанных/Forms/КлиентскийКонструктор.xml new file mode 100644 index 0000000..4ec950c --- /dev/null +++ b/src/cfe/YAXUnit/DataProcessors/ЮТКонструкторТестовыхДанных/Forms/КлиентскийКонструктор.xml @@ -0,0 +1,22 @@ + + +
+ + КлиентскийКонструктор + + + ru + Клиентский конструктор + + + + Managed + false + + PlatformApplication + MobilePlatformApplication + + + +
+
\ No newline at end of file diff --git a/src/cfe/YAXUnit/DataProcessors/ЮТКонструкторТестовыхДанных/Forms/КлиентскийКонструктор/Ext/Form.xml b/src/cfe/YAXUnit/DataProcessors/ЮТКонструкторТестовыхДанных/Forms/КлиентскийКонструктор/Ext/Form.xml new file mode 100644 index 0000000..c1f2bc2 --- /dev/null +++ b/src/cfe/YAXUnit/DataProcessors/ЮТКонструкторТестовыхДанных/Forms/КлиентскийКонструктор/Ext/Form.xml @@ -0,0 +1,6 @@ + +
+ false + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/DataProcessors/ЮТКонструкторТестовыхДанных/Forms/КлиентскийКонструктор/Ext/Form/Module.bsl b/src/cfe/YAXUnit/DataProcessors/ЮТКонструкторТестовыхДанных/Forms/КлиентскийКонструктор/Ext/Form/Module.bsl new file mode 100644 index 0000000..649aedb --- /dev/null +++ b/src/cfe/YAXUnit/DataProcessors/ЮТКонструкторТестовыхДанных/Forms/КлиентскийКонструктор/Ext/Form/Module.bsl @@ -0,0 +1,277 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +// BSLLS:NonStandardRegion-off +#Область ОписаниеПеременных + +// см. ЮТКонструкторТестовыхДанныхСлужебный.НовыйКонтекстКонструктора +&НаКлиенте +Перем Контекст; + +#КонецОбласти + +//@skip-check module-structure-top-region +#Область ПрограммныйИнтерфейс + +// Устанавливает значение реквизита создаваемого объекта. +// +// Если метод вызывается после вызова см. ТабличнаяЧасть, то устанавливается значение реквизита строки табличной части +// +// Параметры: +// ИмяРеквизита - Строка - Имя реквизита объекта или табличной части +// Значение - Произвольный - Значение реквизита объекта или табличной части +// +// Возвращаемое значение: +// ОбщийМодуль - Конструктор +&НаКлиенте +Функция Установить(ИмяРеквизита, Значение) Экспорт + + ЮТКонструкторТестовыхДанныхСлужебный.Установить(Контекст, ИмяРеквизита, Значение); + Возврат ЭтотОбъект; + +КонецФункции + +// Устанавливает значения реквизитов создаваемого объекта. +// +// Если метод вызывается после вызова см. ТабличнаяЧасть, то устанавливаются значения реквизитов строки табличной части +// +// Параметры: +// ЗначенияРеквизитов - Структура - Устанавливаемые значения реквизитов +// +// Возвращаемое значение: +// ОбщийМодуль - Установить реквизиты +&НаКлиенте +Функция УстановитьРеквизиты(ЗначенияРеквизитов) Экспорт + + ЮТКонструкторТестовыхДанныхСлужебный.УстановитьРеквизиты(Контекст, ЗначенияРеквизитов); + Возврат ЭтотОбъект; + +КонецФункции + +// Устанавливает фиктивное значение реквизита создаваемого объекта. +// +// Если метод вызывается после вызова см. ТабличнаяЧасть, то устанавливается значение реквизита строки табличной части. +// +// На основании менеджера и имени реквизита вычисляется его тип, а по типу генерируется фиктивное значение. +// +// * Для примитивных значение генерируется случайное значение +// * Для ссылочных типов создается новый объект +// * Для перечислений (в том числе системных) выбирается случайно значение перечисления +// +// Параметры: +// ИмяРеквизита - Строка - Имя реквизита объекта или табличной части +// РеквизитыЗаполнения - Структура - Значения реквизитов заполнения создаваемого объекта базы +// - Неопределено +// ОграничениеТипа - Тип, ОписаниеТипов - Испольуется для ограничения типа составного реквизита, будет сгерерировано значение указанного типа +// - Неопределено - Будет сгенерировано значение, на основании типа реквизита, если реквизит составной, то будет использован случайный тип +// +// Возвращаемое значение: +// ОбщийМодуль - Конструктор +&НаКлиенте +Функция Фикция(ИмяРеквизита, РеквизитыЗаполнения = Неопределено, ОграничениеТипа = Неопределено) Экспорт + + ЮТКонструкторТестовыхДанныхСлужебный.Фикция(Контекст, ИмяРеквизита, РеквизитыЗаполнения, ОграничениеТипа); + Возврат ЭтотОбъект; + +КонецФункции + +// Заполняет обязательные поля объекта фиктивными значениями +// +// Если метод вызывается после вызова см. ТабличнаяЧасть, то устанавливаются значения реквизитов строки табличной части. +// +// На основании метаданных определяются обязательные поля (Проверка заполнения = Выдавать ошибку), +// для них генерируются и устанавливаются фиктивные значение. +// +// * Для примитивных значение генерируется случайное значение +// * Для ссылочных типов создается новый объект +// * Для перечислений (в том числе системных) выбирается случайно значение перечисления +// +// Возвращаемое значение: +// ОбщийМодуль - Конструктор +&НаКлиенте +Функция ФикцияОбязательныхПолей() Экспорт + + ЮТКонструкторТестовыхДанныхСлужебный.ФикцияОбязательныхПолей(Контекст); + Возврат ЭтотОбъект; + +КонецФункции + +// Переключает конструктор на заполнение табличной части объекта. +// +// Параметры: +// ИмяТабличнойЧасти - Строка - Имя табличной части +// +// Возвращаемое значение: +// ОбщийМодуль - Конструктор +&НаКлиенте +Функция ТабличнаяЧасть(ИмяТабличнойЧасти) Экспорт + + ЮТКонструкторТестовыхДанныхСлужебный.ТабличнаяЧасть(Контекст, ИмяТабличнойЧасти); + Возврат ЭтотОбъект; + +КонецФункции + +// Переключает конструктор на заполнение объекта. +// +// Возвращаемое значение: +// ОбщийМодуль - Конструктор +&НаКлиенте +Функция Объект() Экспорт + + ЮТКонструкторТестовыхДанныхСлужебный.ТабличнаяЧасть(Контекст, Неопределено); + Возврат ЭтотОбъект; + +КонецФункции + +// Добавляет новую строку табличной части объекта. +// При необходимости можно выполнить установку реквизитов новой строки +// +// Параметры: +// ЗначенияРеквизитов - Структура - Устанавливаемые значения реквизитов новой строки +// +// Возвращаемое значение: +// ОбщийМодуль - Конструктор +&НаКлиенте +Функция ДобавитьСтроку(ЗначенияРеквизитов = Неопределено) Экспорт + + ЮТКонструкторТестовыхДанныхСлужебный.ДобавитьСтроку(Контекст, ЗначенияРеквизитов); + Возврат ЭтотОбъект; + +КонецФункции + +// Устанавливает дополнительное свойство объекта. +// +// Параметры: +// ИмяСвойства - Строка - Имя дополнительного свойства +// Значение - Произвольный - Значение дополнительного свойства +// +// Возвращаемое значение: +// ОбщийМодуль - Конструктор +&НаКлиенте +Функция УстановитьДополнительноеСвойство(ИмяСвойства, Значение = Неопределено) Экспорт + + ЮТКонструкторТестовыхДанныхСлужебный.УстановитьДополнительноеСвойство(Контекст, ИмяСвойства, Значение); + Возврат ЭтотОбъект; + +КонецФункции + +// Создает новый объект и возвращает его или ссылку. +// +// Важно, после создания данные не очищаются, поэтому многократный вызов метода создаст множество одинаковых объектов. +// Если вы хотите создать полностью новый объект, необходимо по-новой инициировать конструктор. +// +// Параметры: +// ВернутьОбъект - Булево - Вернуть объект вместо ссылки +// ОбменДаннымиЗагрузка - Булево - Записать объект с признаком `ОбменДанными.Загрузка = Истина` +// +// Возвращаемое значение: +// Произвольный - Созданный объект или ссылка на него +&НаКлиенте +Функция Записать(ВернутьОбъект = Ложь, ОбменДаннымиЗагрузка = Ложь) Экспорт + + Возврат ЮТКонструкторТестовыхДанныхСлужебный.Записать(Контекст, ВернутьОбъект, ОбменДаннымиЗагрузка); + +КонецФункции + +// Создает новый объект. +// +// Важно, после создания данные не очищаются, поэтому многократный вызов метода создаст множество одинаковых объектов. +// Если вы хотите создать полностью новый объект, необходимо по-новой инициировать конструктор. +// +// Параметры: +// ОбменДаннымиЗагрузка - Булево - Записать объект с признаком `ОбменДанными.Загрузка = Истина` +// +// Возвращаемое значение: +// ОбщийМодуль - Конструктор +&НаКлиенте +Функция ДобавитьЗапись(ОбменДаннымиЗагрузка = Ложь) Экспорт + + ЮТКонструкторТестовыхДанныхСлужебный.Записать(Контекст, Ложь, ОбменДаннымиЗагрузка); + + Возврат ЭтотОбъект; + +КонецФункции + +// Создает и возвращяет новый объект (не записывая его). +// +// Важно, после создания данные не очищаются, поэтому многократный вызов метода создаст множество одинаковых объектов. +// Если вы хотите создать полностью новый объект, необходимо по-новой инициировать конструктор. +// +// Возвращаемое значение: +// Произвольный - Созданный объект. +&НаКлиенте +Функция НовыйОбъект() Экспорт + + Возврат ЮТКонструкторТестовыхДанныхСлужебный.НовыйОбъект(Контекст); + +КонецФункции + +// Создает и проводит новый документ. Возвращает объект или или ссылку на него. +// +// Важно, после создания данные не очищаются, поэтому многократный вызов метода создать множество объектов. +// Если вы хотите создать полностью новый объект, необходимо по-новой инициировать конструктор. +// +// Параметры: +// ВернутьОбъект - Булево - Вернуть объект вместо ссылки +// +// Возвращаемое значение: +// Произвольный - Созданный объект или ссылка на него +&НаКлиенте +Функция Провести(ВернутьОбъект = Ложь) Экспорт + + Возврат ЮТКонструкторТестовыхДанныхСлужебный.Провести(Контекст, ВернутьОбъект); + +КонецФункции + +// Возвращает данные текущей строки табличной части объекта. +// +// Возвращаемое значение: +// - Структура - Данные строки +// - Неопределено - Если заполняется объект +&НаКлиенте +Функция ДанныеСтроки() Экспорт + + Возврат ЮТКонструкторТестовыхДанныхСлужебный.ДанныеСтроки(Контекст); + +КонецФункции + +// Возвращает данные создаваемого объекта. +// +// Возвращаемое значение: +// Структура - Данные объекта +&НаКлиенте +Функция ДанныеОбъекта() Экспорт + + Возврат ЮТКонструкторТестовыхДанныхСлужебный.ДанныеОбъекта(Контекст); + +КонецФункции + +#КонецОбласти + +//@skip-check module-structure-top-region +#Область СлужебныйПрограммныйИнтерфейс + +&НаКлиенте +Процедура Инициализировать(Менеджер) Экспорт + + Контекст = ЮТКонструкторТестовыхДанныхСлужебный.НовыйКонтекстКонструктора(Менеджер); + +КонецПроцедуры + +#КонецОбласти +// BSLLS:NonStandardRegion-on diff --git a/src/cfe/YAXUnit/DataProcessors/ЮТЮнитТесты.xml b/src/cfe/YAXUnit/DataProcessors/ЮТЮнитТесты.xml new file mode 100644 index 0000000..68e5199 --- /dev/null +++ b/src/cfe/YAXUnit/DataProcessors/ЮТЮнитТесты.xml @@ -0,0 +1,83 @@ + + + + + + 5b4ab199-21bb-4d2c-9b3f-76400ff90d09 + 46e26617-02e4-4719-87a0-982b4820504f + + + cea40759-07dd-409f-8c26-be7e738c7fbe + e3a7e7ca-1e0d-4fdf-9390-258825a6bba5 + + + + ЮТЮнитТесты + + + ru + Юнит-тесты + + + + false + DataProcessor.ЮТЮнитТесты.Form.Основная + + false + + + + +
Основная
+
СозданиеНастройки
+
Сравнение
+ + + + + ЗапускТестов + + + ru + Запуск тестирования + + + + NavigationPanelImportant + + Single + false + PictureAndText + + + CommonPicture.ЮТЗапустить + false + + + Auto + + + + + СформироватьНастройкиТестирования + + + ru + Сформировать настройки тестирования + + + + NavigationPanelOrdinary + + Single + false + Auto + + + + Auto + + +
+
+
\ No newline at end of file diff --git a/src/cfe/YAXUnit/DataProcessors/ЮТЮнитТесты/Commands/ЗапускТестов/Ext/CommandModule.bsl b/src/cfe/YAXUnit/DataProcessors/ЮТЮнитТесты/Commands/ЗапускТестов/Ext/CommandModule.bsl new file mode 100644 index 0000000..1b635e3 --- /dev/null +++ b/src/cfe/YAXUnit/DataProcessors/ЮТЮнитТесты/Commands/ЗапускТестов/Ext/CommandModule.bsl @@ -0,0 +1,35 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2023 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область ОбработчикиСобытий + +&НаКлиенте +Процедура ОбработкаКоманды(ПараметрКоманды, ПараметрыВыполненияКоманды) + + ПараметрыОткрытия = Новый Структура("ЗагрузитьТесты", Истина); + + ОткрытьФорму("Обработка.ЮТЮнитТесты.Форма.Основная", + ПараметрыОткрытия, + ПараметрыВыполненияКоманды.Источник, + ПараметрыВыполненияКоманды.Уникальность, + ПараметрыВыполненияКоманды.Окно, + ПараметрыВыполненияКоманды.НавигационнаяСсылка); + +КонецПроцедуры + +#КонецОбласти diff --git a/src/cfe/YAXUnit/DataProcessors/ЮТЮнитТесты/Commands/СформироватьНастройкиТестирования/Ext/CommandModule.bsl b/src/cfe/YAXUnit/DataProcessors/ЮТЮнитТесты/Commands/СформироватьНастройкиТестирования/Ext/CommandModule.bsl new file mode 100644 index 0000000..1278ad3 --- /dev/null +++ b/src/cfe/YAXUnit/DataProcessors/ЮТЮнитТесты/Commands/СформироватьНастройкиТестирования/Ext/CommandModule.bsl @@ -0,0 +1,33 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2023 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область ОбработчикиСобытий + +&НаКлиенте +Процедура ОбработкаКоманды(ПараметрКоманды, ПараметрыВыполненияКоманды) + + ОткрытьФорму("Обработка.ЮТЮнитТесты.Форма.СозданиеНастройки", + , + ПараметрыВыполненияКоманды.Источник, + ПараметрыВыполненияКоманды.Уникальность, + ПараметрыВыполненияКоманды.Окно, + ПараметрыВыполненияКоманды.НавигационнаяСсылка); + +КонецПроцедуры + +#КонецОбласти diff --git a/src/cfe/YAXUnit/DataProcessors/ЮТЮнитТесты/Forms/Основная.xml b/src/cfe/YAXUnit/DataProcessors/ЮТЮнитТесты/Forms/Основная.xml new file mode 100644 index 0000000..2a3b9e3 --- /dev/null +++ b/src/cfe/YAXUnit/DataProcessors/ЮТЮнитТесты/Forms/Основная.xml @@ -0,0 +1,22 @@ + + +
+ + Основная + + + ru + Основная + + + + Managed + false + + PlatformApplication + MobilePlatformApplication + + + +
+
\ No newline at end of file diff --git a/src/cfe/YAXUnit/DataProcessors/ЮТЮнитТесты/Forms/Основная/Ext/Form.xml b/src/cfe/YAXUnit/DataProcessors/ЮТЮнитТесты/Forms/Основная/Ext/Form.xml new file mode 100644 index 0000000..c3a0206 --- /dev/null +++ b/src/cfe/YAXUnit/DataProcessors/ЮТЮнитТесты/Forms/Основная/Ext/Form.xml @@ -0,0 +1,929 @@ + +
+ Use + None + + + ПриОткрытии + ПриСозданииНаСервере + + + + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Группа1</v8:content> + </v8:item> + + Item.ДеревоТестов + + + + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Группа1</v8:content> + </v8:item> + + Compact + + + + + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content> </v8:content> + </v8:item> + + + StdPicture.GenerateReport + true + + Text + + + + + + + + + + + + + + + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Группа1</v8:content> + </v8:item> + + Horizontal + Usual + None + false + + + + Tree + None + true + false + false + false + 3 + false + false + true + AsFile + ДеревоТестов + ДеревоТестов.ТипОбъекта + + CommonPicture.ЮТЭлементыТестов + false + + None + None + + false + + + + + + + + + ДеревоТестов + SearchStringRepresentation + + + + + + + ДеревоТестов + ViewStatusRepresentation + + + + + + + ДеревоТестов + SearchControl + + + + + + ДеревоТестовПриАктивизацииСтроки + + + + ДеревоТестов.Представление + 10 + + + + + + ДеревоТестов.Контекст + + + + + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Дерево тестов группа1</v8:content> + </v8:item> + + 30 + + + + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Дерево тестов группа состояние</v8:content> + </v8:item> + + InCell + + + + ДеревоТестов.Иконка + None + 5 + false + AsFile + + + + + ДеревоТестов.Состояние + + + + + + + ДеревоТестов.Прогресс + 2 + false + Stretch + AsFile + + + + + + + ДеревоТестов.ПредставлениеВремяВыполнения + 2 + + + + +
+ + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Группа1</v8:content> + </v8:item> + + Vertical + Usual + None + false + + + + ФорматВыводаОшибки + Right + Tumbler + + + + ФорматВыводаОшибкиПриИзменении + + + + List + None + false + false + false + 2 + false + false + false + false + AsFile + Items.ДеревоТестов.CurrentData.Ошибки + style:FormBackColor + None + None + + + + + + + ДеревоТестовОшибки + SearchStringRepresentation + + + + + + + ДеревоТестовОшибки + ViewStatusRepresentation + + + + + + + ДеревоТестовОшибки + SearchControl + + + + + + + Items.ДеревоТестов.CurrentData.Ошибки.Сообщение + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Сообщения</v8:content> + </v8:item> + + + + + +
+ + Items.ДеревоТестовОшибки.CurrentData.Стек + false + None + true + false + false + style:FormBackColor + + + + + ОтображениеОшибки + None + style:FormBackColor + + false + + + + + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Группа1</v8:content> + </v8:item> + + true + Right + + + + + +
+
+
+
+ + false + false + + + + +
+ + + + cfg:DataProcessorObject.ЮТЮнитТесты + + true + + + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Дерево тестов</v8:content> + </v8:item> + + + v8:ValueTree + + + + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Представление</v8:content> + </v8:item> + + + xs:string + + 0 + Variable + + + + + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Состояние</v8:content> + </v8:item> + + + xs:string + + 0 + Variable + + + + + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Время выполнения</v8:content> + </v8:item> + + + xs:string + + 0 + Variable + + + + + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Иконка</v8:content> + </v8:item> + + + v8ui:Picture + + + + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Ошибки</v8:content> + </v8:item> + + + v8:ValueTable + + + + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Прогресс</v8:content> + </v8:item> + + + v8ui:Picture + + + + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Набор</v8:content> + </v8:item> + + + xs:boolean + + + + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Контекст</v8:content> + </v8:item> + + + xs:string + + 0 + Variable + + + + + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Тип объекта</v8:content> + </v8:item> + + + xs:decimal + + 1 + 0 + Any + + + + + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Время выполнения</v8:content> + </v8:item> + + + xs:decimal + + 10 + 0 + Any + + + + + + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Сообщение</v8:content> + </v8:item> + + + xs:string + + 0 + Variable + + + + + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Стек</v8:content> + </v8:item> + + + xs:string + + 0 + Variable + + + + + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Ожидаемое значение</v8:content> + </v8:item> + + + xs:string + + 0 + Variable + + + + + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Фактическое значение</v8:content> + </v8:item> + + + xs:string + + 0 + Variable + + + + + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Лог</v8:content> + </v8:item> + + + v8:ValueListType + + + + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Тип ошибки</v8:content> + </v8:item> + + + xs:string + + 0 + Variable + + + + + + + + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Адрес отчета</v8:content> + </v8:item> + + + xs:string + + 0 + Variable + + + + + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Загрузить тесты при открытии</v8:content> + </v8:item> + + + xs:boolean + + + + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Отображение ошибки</v8:content> + </v8:item> + + + xs:string + + 0 + Variable + + + + + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Формат вывода ошибки</v8:content> + </v8:item> + + + xs:string + + 0 + Variable + + + true + + ФорматВыводаОшибки + + + + + + + ДеревоТестовПрогресс + + + + + ДеревоТестов.Набор + Equal + false + + + + + Видимость + false + + + + + ru + Скрытие колонок. Тест + + + + + + + ДеревоТестовИконка + + + ДеревоТестовСостояние + + + + + ДеревоТестов.Набор + Equal + true + + + + + Видимость + false + + + + + ru + Скрытие колонок. Набор + + + + + + + ДеревоТестовКонтекст + + + + + ДеревоТестов.Контекст + Equal + Сервер + + + + + ЦветТекста + #B46C00 + + + + + ru + Контекст. Сервер + + + + + + + ДеревоТестовКонтекст + + + + + ДеревоТестов.Контекст + Equal + Клиент + + + + + ЦветТекста + #058BC0 + + + + + ru + Контекст. Клиент + + + + + + + ДеревоТестовВремяВыполнения + + + + + OrGroup + + AndGroup + + ДеревоТестов.Набор + Equal + false + + + ДеревоТестов.ВремяВыполнения + Greater + 1000 + + + + AndGroup + + ДеревоТестов.Набор + Equal + true + + + ДеревоТестов.ВремяВыполнения + Greater + 10000 + + + + + + + ЦветТекста + #D2000F + + + + + ru + Время выполнения > 1 сек + + + + + + + + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Сравнить</v8:content> + </v8:item> + + + CommonPicture.ЮТСравнить + false + + Сравнить + TextPicture + Use + ДеревоТестовОшибки + + + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Сформировать настройки</v8:content> + </v8:item> + + + StdPicture.ReportSettings + true + + СформироватьНастройки + TextPicture + DontUse + + + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Запустить все тесты</v8:content> + </v8:item> + + + CommonPicture.ЮТЗапустить + false + + ЗапуститьВсеТесты + TextPicture + DontUse + + + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Замер времени выполнения</v8:content> + </v8:item> + + + StdPicture.BusinessProcessStart + true + + ЗамерВремениВыполнения + TextPicture + DontUse + + + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Выбранные тесты</v8:content> + </v8:item> + + + CommonPicture.ЮТЗапустить + false + + ЗапуститьВыделенныеТесты + TextPicture + DontUse + + + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Перезапустить упавшие тесты</v8:content> + </v8:item> + + + CommonPicture.ЮТПерезапуститьУпавшие + false + + ПерезапуститьУпавшиеТесты + TextPicture + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/DataProcessors/ЮТЮнитТесты/Forms/Основная/Ext/Form/Module.bsl b/src/cfe/YAXUnit/DataProcessors/ЮТЮнитТесты/Forms/Основная/Ext/Form/Module.bsl new file mode 100644 index 0000000..be892c9 --- /dev/null +++ b/src/cfe/YAXUnit/DataProcessors/ЮТЮнитТесты/Forms/Основная/Ext/Form/Module.bsl @@ -0,0 +1,986 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область ОписаниеПеременных + +&НаКлиенте +Перем ИсполняемыеТестовыеМодули; + +&НаКлиенте +Перем ПараметрыЗапускаТестирования; + +#КонецОбласти + +#Область ОбработчикиСобытийФормы + +&НаСервере +Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка) + + Если Параметры.Свойство("АдресХранилища") И ЭтоАдресВременногоХранилища(Параметры.АдресХранилища) Тогда + АдресОтчета = Параметры.АдресХранилища; + КонецЕсли; + + Параметры.Свойство("ЗагрузитьТесты", ЗагрузитьТестыПриОткрытии); + + Для Каждого Формат Из ФорматыВыводаОшибки() Цикл + Элементы.ФорматВыводаОшибки.СписокВыбора.Добавить(Формат.Ключ, Формат.Ключ); + КонецЦикла; + +КонецПроцедуры + +&НаКлиенте +Процедура ПриОткрытии(Отказ) + + Если ЗначениеЗаполнено(АдресОтчета) Тогда + ДанныеОтчета = ДанныеОтчета(АдресОтчета); + ПослеЗагрузкиТестов(ДанныеОтчета.РезультатыТестирования, ДанныеОтчета.ПараметрыЗапуска); + ИначеЕсли ЗагрузитьТестыПриОткрытии Тогда + ЗагрузитьТесты(); + КонецЕсли; + + ПереключитьВыводОшибки(); + +КонецПроцедуры + +#КонецОбласти + +#Область ОбработчикиСобытийЭлементовШапкиФормы + +&НаКлиенте +Процедура ФорматВыводаОшибкиПриИзменении(Элемент) + + ПереключитьВыводОшибки(); + +КонецПроцедуры + +#КонецОбласти + +#Область ОбработчикиСобытийЭлементовТаблицыФормыДеревоТестов + +&НаКлиенте +Процедура ДеревоТестовПриАктивизацииСтроки(Элемент) + + Данные = Элементы.ДеревоТестов.ТекущиеДанные; + + Если Данные = Неопределено Тогда + Возврат; + КонецЕсли; + + Если Данные.Ошибки.Количество() Тогда + Элементы.ДеревоТестовОшибки.ТекущаяСтрока = Данные.Ошибки[0].ПолучитьИдентификатор(); + КонецЕсли; + + ОтобразитьДанныеОшибки(); + ОбновитьДоступностьСравнения(); + +КонецПроцедуры + +#КонецОбласти + +#Область ОбработчикиКомандФормы + +&НаКлиенте +Процедура Сравнить(Команда) + + Данные = ДанныеТекущейОшибки(); + + Если Данные = Неопределено ИЛИ ПустаяСтрока(Данные.ОжидаемоеЗначение) И ПустаяСтрока(Данные.ФактическоеЗначение) Тогда + Возврат; + КонецЕсли; + + ПараметрыФормы = Новый Структура("ОжидаемоеЗначение, ФактическоеЗначение", Данные.ОжидаемоеЗначение, Данные.ФактическоеЗначение); + + ОткрытьФорму("Обработка.ЮТЮнитТесты.Форма.Сравнение", ПараметрыФормы, ЭтотОбъект, , , , , РежимОткрытияОкнаФормы.БлокироватьОкноВладельца); + +КонецПроцедуры + +&НаКлиенте +Процедура СформироватьНастройки(Команда) + + ОткрытьФорму("Обработка.ЮТЮнитТесты.Форма.СозданиеНастройки", , ЭтотОбъект); + +КонецПроцедуры + +&НаКлиенте +Процедура ЗамерВремениВыполнения(Команда) + + Обработчик = Новый ОписаниеОповещения("ПослеВодаКоличестваИтерацийЗамера", ЭтотОбъект); + ПоказатьВводЧисла(Обработчик, 100, "Укажите количество итераций замера", 3, 0); + +КонецПроцедуры + +&НаКлиенте +Процедура ЗапуститьВсеТесты(Команда) + + ВыполнитьТестовыеМодули(ИсполняемыеТестовыеМодули); + +КонецПроцедуры + +&НаКлиенте +Процедура ПерезапуститьУпавшиеТесты(Команда) + + СтатусыИсполненияТеста = ЮТФабрика.СтатусыИсполненияТеста(); + Статусы = ЮТКоллекции.ЗначениеВМассиве(СтатусыИсполненияТеста.Ошибка, СтатусыИсполненияТеста.Сломан); + + Модули = МодулиСоответствующиеСтатусу(Статусы); + ВыполнитьТестовыеМодули(Модули); + +КонецПроцедуры + +&НаКлиенте +Процедура ЗапуститьВыделенныеТесты(Команда) + + Модули = ВыделенныеТестовыеМодули(); + ВыполнитьТестовыеМодули(Модули); + +КонецПроцедуры + +#КонецОбласти + +#Область СлужебныеПроцедурыИФункции + +#Область ВыводОтчета + +&НаСервереБезКонтекста +Функция ДанныеОтчета(Знач АдресХранилища) + + Данные = ПолучитьИзВременногоХранилища(АдресХранилища); + УдалитьИзВременногоХранилища(АдресХранилища); + + Возврат Данные; + +КонецФункции + +&НаКлиенте +Процедура ОтобразитьРезультатТеста(СтрокаТеста, Тест, Набор) + + СтрокаТеста.Представление = Тест.Имя; + СтрокаТеста.Контекст = НормализоватьКонтекст(Набор.Режим); + СтрокаТеста.ПредставлениеВремяВыполнения = ЮТОбщий.ПредставлениеПродолжительности(Тест.Длительность); + СтрокаТеста.ВремяВыполнения = Тест.Длительность; + СтрокаТеста.Состояние = Тест.Статус; + СтрокаТеста.ТипОбъекта = 3; + СтрокаТеста.Иконка = КартинкаСтатуса(Тест.Статус); + + ЗаполнитьОшибки(СтрокаТеста, Тест); + +КонецПроцедуры + +&НаКлиенте +Функция ОбновитьСтатистикуНабора(СтрокаНабора) + + СтатистикаНабора = СтатистикаНабора(СтрокаНабора); + Статусы = ЮТФабрика.СтатусыИсполненияТеста(); + + Если СтатистикаНабора.Сломано Тогда + СтрокаНабора.Состояние = Статусы.Сломан; + ИначеЕсли СтатистикаНабора.Упало Тогда + СтрокаНабора.Состояние = Статусы.Ошибка; + ИначеЕсли СтатистикаНабора.Пропущено Тогда + СтрокаНабора.Состояние = Статусы.Пропущен; + ИначеЕсли СтатистикаНабора.Неизвестно Тогда + СтрокаНабора.Состояние = Статусы.Ошибка; + ИначеЕсли СтатистикаНабора.Ожидание Тогда + СтрокаНабора.Состояние = Статусы.Ожидание; + Иначе + СтрокаНабора.Состояние = Статусы.Успешно; + КонецЕсли; + + СтрокаНабора.Прогресс = ГрафическоеПредставлениеСтатистики(СтатистикаНабора); + СтрокаНабора.Иконка = КартинкаСтатуса(СтрокаНабора.Состояние); + + СтрокаНабора.ПредставлениеВремяВыполнения = ЮТОбщий.ПредставлениеПродолжительности(СтатистикаНабора.Продолжительность); + СтрокаНабора.ВремяВыполнения = СтатистикаНабора.Продолжительность; + + Возврат СтатистикаНабора; + +КонецФункции + +&НаКлиенте +Процедура ОбновитьОбщуюСтатистику(ОбновлятьСтатистикуНаборов) + + ОбщаяСтатистика = Статистика(); + + Для Каждого СтрокаНабора Из ДеревоТестов.ПолучитьЭлементы() Цикл + + Если ОбновлятьСтатистикуНаборов Тогда + СтатистикаНабора = ОбновитьСтатистикуНабора(СтрокаНабора); + Иначе + СтатистикаНабора = СтатистикаНабора(СтрокаНабора); + КонецЕсли; + + Для Каждого Элемент Из СтатистикаНабора Цикл + ЮТОбщий.Инкремент(ОбщаяСтатистика[Элемент.Ключ], Элемент.Значение); + КонецЦикла; + + КонецЦикла; + + Элементы.СтатистикаВыполнения.Заголовок = ПредставлениеСтатистики(ОбщаяСтатистика); + +КонецПроцедуры + +&НаКлиенте +Функция СтатистикаНабора(СтрокаНабора) + + СтатистикаНабора = Статистика(); + Статусы = ЮТФабрика.СтатусыИсполненияТеста(); + + Для Каждого СтрокаТеста Из СтрокаНабора.ПолучитьЭлементы() Цикл + + ИнкрементСтатистики(СтатистикаНабора, СтрокаТеста.Состояние, Статусы); + ЮТОбщий.Инкремент(СтатистикаНабора.Продолжительность, СтрокаТеста.ВремяВыполнения); + + КонецЦикла; + + Возврат СтатистикаНабора; + +КонецФункции + +&НаКлиентеНаСервереБезКонтекста +Процедура ЗаполнитьОшибки(СтрокаДерева, ОписаниеОбъекта) + + СтрокаДерева.Ошибки.Очистить(); + Для Каждого Ошибка Из ОписаниеОбъекта.Ошибки Цикл + + СтрокаОшибки = СтрокаДерева.Ошибки.Добавить(); + ЗаполнитьЗначенияСвойств(СтрокаОшибки, Ошибка); + СтрокаОшибки.Лог.ЗагрузитьЗначения(Ошибка.Лог); + СтрокаОшибки.ОжидаемоеЗначение = ЮТКоллекции.ЗначениеСтруктуры(Ошибка, "ОжидаемоеЗначение"); + СтрокаОшибки.ФактическоеЗначение = ЮТКоллекции.ЗначениеСтруктуры(Ошибка, "ПроверяемоеЗначение"); + + КонецЦикла; + +КонецПроцедуры + +&НаКлиенте +Функция Статистика() + + Статистика = Новый Структура(); + Статистика.Вставить("Всего", 0); + Статистика.Вставить("Успешно", 0); + Статистика.Вставить("Упало", 0); + Статистика.Вставить("Сломано", 0); + Статистика.Вставить("Пропущено", 0); + Статистика.Вставить("Ожидание", 0); + Статистика.Вставить("Неизвестно", 0); + Статистика.Вставить("Продолжительность", 0); + + Возврат Статистика; + +КонецФункции + +&НаКлиентеНаСервереБезКонтекста +Функция НормализоватьКонтекст(Контекст) + + Если СтрНачинаетсяС(Контекст, "Клиент") Тогда + Возврат "Клиент"; + Иначе + Возврат Контекст; + КонецЕсли; + +КонецФункции + +&НаКлиентеНаСервереБезКонтекста +Процедура ИнкрементСтатистики(Статистика, Статус, Знач Статусы = Неопределено) + + Если Статусы = Неопределено Тогда + Статусы = ЮТФабрика.СтатусыИсполненияТеста(); + КонецЕсли; + + ЮТОбщий.Инкремент(Статистика.Всего); + + Если Статус = Статусы.Успешно Тогда + + ЮТОбщий.Инкремент(Статистика.Успешно); + + ИначеЕсли Статус = Статусы.Сломан ИЛИ Статус = Статусы.НеРеализован Тогда + + ЮТОбщий.Инкремент(Статистика.Сломано); + + ИначеЕсли Статус = Статусы.Ошибка Тогда + + ЮТОбщий.Инкремент(Статистика.Упало); + + ИначеЕсли Статус = Статусы.Пропущен Тогда + + ЮТОбщий.Инкремент(Статистика.Пропущено); + + ИначеЕсли Статус = Статусы.Ожидание Тогда + + ЮТОбщий.Инкремент(Статистика.Ожидание); + + Иначе + + ЮТОбщий.Инкремент(Статистика.Неизвестно); + + КонецЕсли; + +КонецПроцедуры + +#КонецОбласти + +#Область Интерфейсное + +&НаСервереБезКонтекста +Функция КартинкаСтатуса(Статус) + + Статусы = ЮТФабрика.СтатусыИсполненияТеста(); + + Если Статус = Статусы.Успешно Тогда + + Возврат БиблиотекаКартинок.ЮТУспешно; + + ИначеЕсли Статус = Статусы.Сломан ИЛИ Статус = Статусы.НеРеализован Тогда + + Возврат БиблиотекаКартинок.ЮТОшибка; + + ИначеЕсли Статус = Статусы.Ошибка Тогда + + Возврат БиблиотекаКартинок.ЮТУпал; + + ИначеЕсли Статус = Статусы.Пропущен Тогда + + Возврат БиблиотекаКартинок.ЮТПропущен; + + Иначе + + Возврат БиблиотекаКартинок.ЮТНеизвестный; + + КонецЕсли; + +КонецФункции + +&НаСервереБезКонтекста +Функция ПредставлениеСтатистики(Статистика) + + БлокиСтатистики = Новый Массив(); + Разделитель = "; "; + + БлокиСтатистики.Добавить(СтрШаблон("Тестов: %1/%2", Статистика.Всего - Статистика.Пропущено - Статистика.Ожидание, Статистика.Всего)); + + Если Статистика.Ожидание Тогда + БлокиСтатистики.Добавить(Разделитель); + БлокиСтатистики.Добавить(БиблиотекаКартинок.ЮТНеизвестный); + БлокиСтатистики.Добавить(" Ожидание: " + Статистика.Ожидание); + КонецЕсли; + + Если Статистика.Пропущено Тогда + БлокиСтатистики.Добавить(Разделитель); + БлокиСтатистики.Добавить(БиблиотекаКартинок.ЮТПропущен); + БлокиСтатистики.Добавить(" Пропущено: " + Статистика.Пропущено); + КонецЕсли; + + БлокиСтатистики.Добавить(Разделитель); + БлокиСтатистики.Добавить(БиблиотекаКартинок.ЮТУспешно); + БлокиСтатистики.Добавить(" Успешно: " + Статистика.Успешно); + + БлокиСтатистики.Добавить(Разделитель); + БлокиСтатистики.Добавить(БиблиотекаКартинок.ЮТОшибка); + БлокиСтатистики.Добавить(" Сломано: " + Статистика.Сломано); + + БлокиСтатистики.Добавить(Разделитель); + БлокиСтатистики.Добавить(БиблиотекаКартинок.ЮТУпал); + БлокиСтатистики.Добавить(" Упало: " + Статистика.Упало); + + Если Статистика.Неизвестно Тогда + БлокиСтатистики.Добавить(Разделитель); + БлокиСтатистики.Добавить(БиблиотекаКартинок.ЮТНеизвестный); + БлокиСтатистики.Добавить(" Неизвестно: " + Статистика.Неизвестно); + КонецЕсли; + + БлокиСтатистики.Добавить(Разделитель); + БлокиСтатистики.Добавить(" Время выполнения: " + ЮТОбщий.ПредставлениеПродолжительности(Статистика.Продолжительность)); + + Возврат Новый ФорматированнаяСтрока(БлокиСтатистики); + +КонецФункции + +&НаСервереБезКонтекста +Функция ГрафическоеПредставлениеСтатистики(Статистика) + + Текст = БлокиСтатистики(Статистика); + + Возврат Новый Картинка(ПолучитьДвоичныеДанныеИзСтроки(Текст)); + +КонецФункции + +&НаСервереБезКонтекста +Функция БлокиСтатистики(Статистика) + + Блоки = Новый Массив(); + Ключи = "Количество, Цвет"; + + Блоки.Добавить(Новый Структура(Ключи, Статистика.Успешно, "25AE88")); + Блоки.Добавить(Новый Структура(Ключи, Статистика.Пропущено, "999999")); + Блоки.Добавить(Новый Структура(Ключи, Статистика.Упало, "EFCE4A")); + Блоки.Добавить(Новый Структура(Ключи, Статистика.Сломано, "D75A4A")); + Блоки.Добавить(Новый Структура(Ключи, Статистика.Ожидание, "BBBBBB")); + Блоки.Добавить(Новый Структура(Ключи, Статистика.Неизвестно, "9400d3")); + + Сдвиг = 0; + Высота = 20; + + Текст = ""; + + Для Инд = 0 По Блоки.ВГраница() Цикл + + Если Блоки[Инд].Количество = 0 Тогда + Продолжить; + КонецЕсли; + + Текст = Текст + СтрШаблон(" + | %7 + |", Сдвиг + 2, Высота * 2 - 4, Высота - 4, Блоки[Инд].Цвет, Сдвиг + Высота, Высота - 4, Блоки[Инд].Количество); + ЮТОбщий.Инкремент(Сдвиг, Высота * 2 + 2); + + КонецЦикла; + + Возврат СтрШаблон(" + | %3 + |", Сдвиг, Высота + 2, Текст); + +КонецФункции + +#КонецОбласти + +#Область ЗагрузкаТестов + +&НаКлиенте +Процедура ЗагрузитьТесты() + + ПараметрыЗапуска = ПараметрыЗапуска(); + + ПараметрыЗагрузки = ЮТИсполнительСлужебныйКлиент.ПараметрыИсполнения(); + ПараметрыЗагрузки.Цепочка.Добавить(Новый ОписаниеОповещения("ПослеЗагрузкиТестов", ЭтотОбъект, ПараметрыЗапуска)); + ПараметрыЗагрузки.ПараметрыЗапуска = ПараметрыЗапуска; + + ЮТИсполнительСлужебныйКлиент.ВыполнитьИнициализацию(ПараметрыЗагрузки.ПараметрыЗапуска); + ЮТИсполнительСлужебныйКлиент.ОбработчикЗагрузитьТесты(Неопределено, ПараметрыЗагрузки); + +КонецПроцедуры + +&НаКлиенте +Процедура ПослеЗагрузкиТестов(Результат, ПараметрыЗапуска) Экспорт + + ИсполняемыеТестовыеМодули = Результат; + ПараметрыЗапускаТестирования = ПараметрыЗапуска; + + Для Каждого ТестовыйМодуль Из ИсполняемыеТестовыеМодули Цикл + + Для Каждого Набор Из ТестовыйМодуль.НаборыТестов Цикл + + СтрокаНабора = ДеревоТестов.ПолучитьЭлементы().Добавить(); + СтрокаНабора.Набор = Истина; + СтрокаНабора.Представление = Набор.Представление; + СтрокаНабора.Контекст = НормализоватьКонтекст(Набор.Режим); + СтрокаНабора.ПредставлениеВремяВыполнения = ЮТОбщий.ПредставлениеПродолжительности(Набор.Длительность); + СтрокаНабора.ВремяВыполнения = Набор.Длительность; + СтрокаНабора.ТипОбъекта = 2; + + ЗаполнитьОшибки(СтрокаНабора, Набор); + + Набор.Вставить("Идентификатор", СтрокаНабора.ПолучитьИдентификатор()); + + Для Каждого Тест Из Набор.Тесты Цикл + + СтрокаТеста = СтрокаНабора.ПолучитьЭлементы().Добавить(); + + ОтобразитьРезультатТеста(СтрокаТеста, Тест, Набор); + + Тест.Вставить("Идентификатор", СтрокаТеста.ПолучитьИдентификатор()); + + КонецЦикла; + + КонецЦикла; + + КонецЦикла; + + ОбновитьОбщуюСтатистику(Истина); + + ЮТКонтекстСлужебный.УдалитьКонтекст(); + +КонецПроцедуры + +#КонецОбласти + +#Область ЗапускТестов + +&НаКлиенте +Процедура ВыполнитьТестовыеМодули(Модули) + + Если Модули.Количество() = 0 Тогда + ПоказатьПредупреждение( , "Нет тестов для запуска"); + Возврат; + КонецЕсли; + + ОповещениеПользователю("Прогон тестов", "Запушено выполнение тестов"); + + ЮТИсполнительСлужебныйКлиент.ВыполнитьИнициализацию(ПараметрыЗапускаТестирования); + ЮТСобытияСлужебный.ПослеФормированияИсполняемыхНаборовТестов(Модули); + ЮТСобытияСлужебный.ПередВыполнениемТестов(Модули); + + Для Каждого Модуль Из Модули Цикл + + СброситьСостояниеТестирования(Модуль); + + Результат = ЮТИсполнительСлужебныйКлиент.ВыполнитьТестыМодуля(Модуль); + + Для Каждого Набор Из Результат.НаборыТестов Цикл + + Для Каждого Тест Из Набор.Тесты Цикл + + Строка = ДеревоТестов.НайтиПоИдентификатору(Тест.Идентификатор); + ОтобразитьРезультатТеста(Строка, Тест, Набор); + + КонецЦикла; + + Строка = ДеревоТестов.НайтиПоИдентификатору(Набор.Идентификатор); + ОбновитьСтатистикуНабора(Строка); + + КонецЦикла; + + КонецЦикла; + + ОбновитьОбщуюСтатистику(Ложь); + + ЮТКонтекстСлужебный.УдалитьКонтекст(); + + ОповещениеПользователю("Прогон тестов завершен", "Завершено выполнение тестов"); + +КонецПроцедуры + +&НаКлиенте +Процедура СброситьСостояниеТестирования(Модуль) + + Статусы = ЮТФабрика.СтатусыИсполненияТеста(); + + Модуль.Ошибки.Очистить(); + + Для Каждого Набор Из Модуль.НаборыТестов Цикл + Набор.Ошибки.Очистить(); + Набор.Выполнять = Истина; + + Для Каждого Тест Из Набор.Тесты Цикл + Тест.Ошибки.Очистить(); + Тест.Статус = Статусы.Ожидание; + КонецЦикла; + КонецЦикла; + +КонецПроцедуры + +&НаКлиенте +Функция ВыделенныеТестовыеМодули() + + МодулиКЗапуску = Новый Массив(); + + ВыделенныеСтроки = Элементы.ДеревоТестов.ВыделенныеСтроки; + + Если ВыделенныеСтроки.Количество() = 0 Тогда + Возврат МодулиКЗапуску; + КонецЕсли; + + Для Каждого Модуль Из ИсполняемыеТестовыеМодули Цикл + + НаборыКЗапуску = Новый Массив(); + + Для Каждого Набор Из Модуль.НаборыТестов Цикл + + Если ВыделенныеСтроки.Найти(Набор.Идентификатор) <> Неопределено Тогда + НаборыКЗапуску.Добавить(Набор); + Продолжить; + КонецЕсли; + + ТестыКЗапуску = Новый Массив(); + + Для Каждого Тест Из Набор.Тесты Цикл + Если ВыделенныеСтроки.Найти(Тест.Идентификатор) <> Неопределено Тогда + ТестыКЗапуску.Добавить(Тест); + КонецЕсли; + КонецЦикла; + + Если ТестыКЗапуску.Количество() Тогда + ЗапускаемыйНабор = ЮТКоллекции.СкопироватьСтруктуру(Набор); + ЗапускаемыйНабор.Тесты = ТестыКЗапуску; + НаборыКЗапуску.Добавить(ЗапускаемыйНабор); + КонецЕсли; + + КонецЦикла; + + Если НаборыКЗапуску.Количество() Тогда + + ЗапускаемыйМодуль = ЮТКоллекции.СкопироватьСтруктуру(Модуль); + ЗапускаемыйМодуль.НаборыТестов = НаборыКЗапуску; + МодулиКЗапуску.Добавить(ЗапускаемыйМодуль); + + КонецЕсли; + + КонецЦикла; + + Возврат МодулиКЗапуску; + +КонецФункции + +&НаКлиенте +Функция МодулиСоответствующиеСтатусу(Статусы) + + МодулиКЗапуску = Новый Массив(); + + Для Каждого Модуль Из ИсполняемыеТестовыеМодули Цикл + + НаборыКЗапуску = Новый Массив(); + + Для Каждого Набор Из Модуль.НаборыТестов Цикл + + ТестыКЗапуску = Новый Массив(); + + Для Каждого Тест Из Набор.Тесты Цикл + Если Статусы.Найти(Тест.Статус) <> Неопределено Тогда + ТестыКЗапуску.Добавить(Тест); + КонецЕсли; + КонецЦикла; + + Если ТестыКЗапуску.Количество() Тогда + ЗапускаемыйНабор = ЮТКоллекции.СкопироватьСтруктуру(Набор); + ЗапускаемыйНабор.Тесты = ТестыКЗапуску; + НаборыКЗапуску.Добавить(ЗапускаемыйНабор); + КонецЕсли; + + КонецЦикла; + + Если НаборыКЗапуску.Количество() Тогда + + ЗапускаемыйМодуль = ЮТКоллекции.СкопироватьСтруктуру(Модуль); + ЗапускаемыйМодуль.НаборыТестов = НаборыКЗапуску; + МодулиКЗапуску.Добавить(ЗапускаемыйМодуль); + + КонецЕсли; + + КонецЦикла; + + Возврат МодулиКЗапуску; + +КонецФункции + +&НаКлиенте +Процедура ВыполнитьЗапускТестовПоПараметрам(ПараметрыЗапуска, Обработчик) + + ЮТИсполнительСлужебныйКлиент.ВыполнитьМодульноеТестированиеПоНастройке(ПараметрыЗапуска, Обработчик); + +КонецПроцедуры + +#КонецОбласти + +#Область ПараметрыЗапуска + +&НаКлиенте +Функция ПараметрыЗапуска() + + ПараметрыЗапуска = ЮТФабрика.ПараметрыЗапуска(); + ПараметрыЗапуска.closeAfterTests = Ложь; + ПараметрыЗапуска.showReport = Ложь; + ПараметрыЗапуска.ВыполнятьМодульноеТестирование = Истина; + + Возврат ПараметрыЗапуска; + +КонецФункции + +#КонецОбласти + +&НаКлиенте +Процедура ОбновитьДоступностьСравнения() + + Данные = ДанныеТекущейОшибки();; + Элементы.Сравнить.Доступность = Данные <> Неопределено И (НЕ ПустаяСтрока(Данные.ОжидаемоеЗначение) ИЛИ НЕ ПустаяСтрока(Данные.ФактическоеЗначение)); + +КонецПроцедуры + +&НаКлиенте +Функция ДанныеТекущейОшибки() + + Данные = Элементы.ДеревоТестовОшибки.ТекущиеДанные; + + Если Данные <> Неопределено Или ФорматВыводаОшибки = ФорматыВыводаОшибки().Текст Тогда + Возврат Данные; + КонецЕсли; + + ДанныеТеста = Элементы.ДеревоТестов.ТекущиеДанные; + + Если ДанныеТеста <> Неопределено И ЗначениеЗаполнено(ДанныеТеста.Ошибки) Тогда + Возврат ДанныеТеста.Ошибки[0]; + КонецЕсли; + +КонецФункции + +&НаКлиенте +Процедура ПослеВодаКоличестваИтерацийЗамера(Результат, ДополнительныеПараметры) Экспорт + + Если НЕ ЗначениеЗаполнено(Результат) Тогда + Возврат; + КонецЕсли; + + ПараметрыЗамера = Новый Структура(); + ПараметрыЗамера.Вставить("ПараметрыЗапуска", ПараметрыЗапуска()); + ПараметрыЗамера.Вставить("КоличествоИтераций", Результат); + ПараметрыЗамера.Вставить("ТекущаяИтерация", 0); + ПараметрыЗамера.Вставить("Замеры", Новый Массив()); + ПараметрыЗамера.Вставить("НачалоИтерации"); + + ПослеВыполненияИтерации(Неопределено, ПараметрыЗамера); + +КонецПроцедуры + +&НаКлиенте +Процедура ПослеВыполненияИтерации(Результат, ПараметрыЗамера) Экспорт + + Если ПараметрыЗамера.ТекущаяИтерация > 0 Тогда + Длительность = ТекущаяУниверсальнаяДатаВМиллисекундах() - ПараметрыЗамера.НачалоИтерации; + ПараметрыЗамера.Замеры.Добавить(Длительность); + КонецЕсли; + + Если ЮТОбщий.Инкремент(ПараметрыЗамера.ТекущаяИтерация) <= ПараметрыЗамера.КоличествоИтераций Тогда + + Обработчик = Новый ОписаниеОповещения("ПослеВыполненияИтерации", ЭтотОбъект, ПараметрыЗамера); + ПараметрыЗамера.НачалоИтерации = ТекущаяУниверсальнаяДатаВМиллисекундах(); + ВыполнитьЗапускТестовПоПараметрам(ПараметрыЗамера.ПараметрыЗапуска, Обработчик); + + Иначе + + ОбщееВремя = 0; + Для Каждого Замер Из ПараметрыЗамера.Замеры Цикл + ЮТОбщий.Инкремент(ОбщееВремя, Замер); + КонецЦикла; + + Список = Новый СписокЗначений(); + Список.ЗагрузитьЗначения(ПараметрыЗамера.Замеры); + Список.СортироватьПоЗначению(); + + ОбщееВремя = Окр(ОбщееВремя / 1000, 2); + СреднееВремя = Окр(ОбщееВремя / ПараметрыЗамера.Замеры.Количество(), 2); + МедианноеВремя = Окр(Список[Цел(Список.Количество() / 2) + 1].Значение / 1000, 2); + + Сообщение = СтрШаблон("Количество итераций: %1 + |Общее время: %2 сек + |Среднее время: %3 сек + |Медианное время: %4 сек", ПараметрыЗамера.Замеры.Количество(), ОбщееВремя, СреднееВремя, МедианноеВремя); + + ЮТОбщий.СообщитьПользователю(Сообщение); + + КонецЕсли; + +КонецПроцедуры + +&НаКлиенте +Процедура ОповещениеПользователю(Текст, Пояснение) + + ПоказатьОповещениеПользователя(Текст, + , + Пояснение, + БиблиотекаКартинок.ЮТПодсистема, + СтатусОповещенияПользователя.Важное, + УникальныйИдентификатор); + +КонецПроцедуры + +#Область ВыводОшибки + +&НаКлиенте +Процедура ПереключитьВыводОшибки() + + Форматы = ФорматыВыводаОшибки(); + Если НЕ ЗначениеЗаполнено(ФорматВыводаОшибки) Тогда + ФорматВыводаОшибки = Форматы.HTML; + КонецЕсли; + + Элементы.ДеревоТестовОшибки.Видимость = ФорматВыводаОшибки = Форматы.Текст; + Элементы.ДеревоТестовОшибкиСтек.Видимость = ФорматВыводаОшибки = Форматы.Текст; + Элементы.ОтображениеОшибки.Видимость = ФорматВыводаОшибки = Форматы.HTML; + + Если ФорматВыводаОшибки = Форматы.HTML Тогда + ОтобразитьДанныеОшибки(); + КонецЕсли; + +КонецПроцедуры + +&НаКлиентеНаСервереБезКонтекста +Функция ФорматыВыводаОшибки() + + Форматы = Новый Структура(); + Форматы.Вставить("Текст", "Текст"); + Форматы.Вставить("HTML", "HTML"); + + Возврат Форматы; + +КонецФункции + +&НаКлиенте +Процедура ОтобразитьДанныеОшибки(); + + ДанныеТеста = Элементы.ДеревоТестов.ТекущиеДанные; + Если ДанныеТеста = Неопределено Или НЕ ЗначениеЗаполнено(ДанныеТеста.Ошибки) Тогда + Если ЭтоАдресВременногоХранилища(ОтображениеОшибки) Тогда + УдалитьИзВременногоХранилища(ОтображениеОшибки); + КонецЕсли; + ОтображениеОшибки = Неопределено; + Возврат; + КонецЕсли; + + ОтображениеОшибки = ДеревоОшибкиHTML(ОтображениеОшибки, ДанныеТеста.Ошибки); + +КонецПроцедуры + +&НаСервереБезКонтекста +Функция ДеревоОшибкиHTML(Знач АдресХранилища, Знач Ошибки) + + Если ЭтоАдресВременногоХранилища(АдресХранилища) Тогда + УдалитьИзВременногоХранилища(АдресХранилища); + КонецЕсли; + + Блоки = Новый Массив(); + + Для Каждого Ошибка Из Ошибки Цикл + ВывестиДанныеОшибки(Блоки, Ошибка); + КонецЦикла; + + ШаблонПредставленияОшибки = ЮТОбщий.Макет("ОбщийМакет.ЮТИнформацияОбОшибке").ПолучитьТекст(); + ПредставленияОшибки = СтрЗаменить(ШаблонПредставленияОшибки, "TREE_CONTENT", СтрСоединить(Блоки, Символы.ПС)); + + Возврат ПолучитьНавигационнуюСсылкуИнформационнойБазы() + "/"+ ПоместитьВоВременноеХранилище(ПредставленияОшибки, Новый УникальныйИдентификатор); + +КонецФункции + +&НаСервереБезКонтекста +Процедура ВывестиДанныеОшибки(Блоки, Ошибка) + + ТипыОшибок = ЮТФабрикаСлужебный.ТипыОшибок(); + Если Ошибка.ТипОшибки = ТипыОшибок.Утверждений Тогда + Класс = "failure"; + ИначеЕсли Ошибка.ТипОшибки = ТипыОшибок.Пропущен Тогда + Класс = "skipped"; + Иначе + Класс = "error"; + КонецЕсли; + + Блоки.Добавить(СтрШаблон("
+ |
+ | + | + |
%2
+ |
+ |", Класс, ЗаменитьСпецСимволы(Ошибка.Сообщение))); + Если ЗначениеЗаполнено(Ошибка.Лог) Или ЗначениеЗаполнено(Ошибка.Стек) Тогда + Блоки.Добавить("
"); + ВывестиЛог(Блоки, Ошибка.Лог); + ВывестиСтек(Блоки, Ошибка.Стек, Класс); + Блоки.Добавить("
"); + КонецЕсли; + Блоки.Добавить("
"); + +КонецПроцедуры + +&НаСервереБезКонтекста +Процедура ВывестиЛог(Блоки, Лог) + + Если НЕ ЗначениеЗаполнено(Лог) Тогда + Возврат; + КонецЕсли; + + Блоки.Добавить("
+ | Лог исполнения + |
"); + Для Каждого Строка Из Лог Цикл + Блоки.Добавить(СтрШаблон("
%1
", ЗаменитьСпецСимволы(Строка))); + КонецЦикла; + Блоки.Добавить("
"); + +КонецПроцедуры + +&НаСервереБезКонтекста +Процедура ВывестиСтек(Блоки, ПредставлениеСтека, Класс) + + Если НЕ ЗначениеЗаполнено(ПредставлениеСтека) Тогда + Возврат; + КонецЕсли; + + Стек = Стек(ПредставлениеСтека); + + Блоки.Добавить(СтрШаблон("
+ |
+ | + | + |
%2
+ |
+ |
+ |", Класс, ЗаменитьСпецСимволы(Стек.Сообщение))); + + Для Каждого Линия Из Стек.Линии Цикл + Блоки.Добавить(СтрШаблон("
+ |
%1
+ |
+ |", ЗаменитьСпецСимволы(Линия))); + КонецЦикла; + + Блоки.Добавить("
"); + +КонецПроцедуры +&НаСервереБезКонтекста +Функция ЗаменитьСпецСимволы(Знач Стр) + + Стр = СтрЗаменить(Стр, "&", "&"); + Стр = СтрЗаменить(Стр, """", """); + Стр = СтрЗаменить(Стр, "<", "<"); + Стр = СтрЗаменить(Стр, ">", ">"); + Стр = СтрЗаменить(Стр, "‘", "'"); + + Возврат СокрЛП(Стр); + +КонецФункции + +&НаСервереБезКонтекста +Функция Стек(Стек) + + Разделитель = Символы.ПС; + Строки = СтрРазделить(Стек, Разделитель); + + Корень = Новый Структура("Сообщение, Линии", Неопределено, Новый Массив()); + + Для Инд = 0 По Строки.ВГраница() Цикл + + Строка = Строки[Инд]; + Если СтрНачинаетсяС(Строка, "{") И СтрНайти(Строка, ")}") Тогда + НомерСтроки = Инд; + Прервать; + КонецЕсли; + + Корень.Сообщение = ЮТСтроки.ДобавитьСтроку(Корень.Сообщение, Строка, Разделитель); + КонецЦикла; + + Для Инд = НомерСтроки По Строки.ВГраница() Цикл + Строка = Строки[Инд]; + Если СтрНачинаетсяС(Строка, "{") И СтрНайти(Строка, ")}") Тогда + Корень.Линии.Добавить(Строка); + КонецЕсли; + КонецЦикла; + + Возврат Корень; + +КонецФункции + +#КонецОбласти + +#КонецОбласти diff --git a/src/cfe/YAXUnit/DataProcessors/ЮТЮнитТесты/Forms/СозданиеНастройки.xml b/src/cfe/YAXUnit/DataProcessors/ЮТЮнитТесты/Forms/СозданиеНастройки.xml new file mode 100644 index 0000000..a4086d6 --- /dev/null +++ b/src/cfe/YAXUnit/DataProcessors/ЮТЮнитТесты/Forms/СозданиеНастройки.xml @@ -0,0 +1,22 @@ + + +
+ + СозданиеНастройки + + + ru + Создание настройки + + + + Managed + false + + PlatformApplication + MobilePlatformApplication + + + +
+
\ No newline at end of file diff --git a/src/cfe/YAXUnit/DataProcessors/ЮТЮнитТесты/Forms/СозданиеНастройки/Ext/Form.xml b/src/cfe/YAXUnit/DataProcessors/ЮТЮнитТесты/Forms/СозданиеНастройки/Ext/Form.xml new file mode 100644 index 0000000..7437c5c --- /dev/null +++ b/src/cfe/YAXUnit/DataProcessors/ЮТЮнитТесты/Forms/СозданиеНастройки/Ext/Form.xml @@ -0,0 +1,577 @@ + +
+ + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Конфигурация запуска тестов</v8:content> + </v8:item> + + Use + false + false + None + + + ПриОткрытии + ПриСозданииНаСервере + + + + Tree + false + false +
false
+ AsFile + ДеревоТестов + ДеревоТестов.ТипОбъекта + + CommonPicture.ЮТЭлементыТестов + false + + + + + + + + + + + + + ДеревоТестов + SearchStringRepresentation + + + + + + + ДеревоТестов + ViewStatusRepresentation + + + + + + + ДеревоТестов + SearchControl + + + + + + + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Дерево тестов группа1</v8:content> + </v8:item> + + InCell + + + + ДеревоТестов.Отметка + None + true + + + + ДеревоТестовОтметкаПриИзменении + + + + ДеревоТестов.Представление + + + + + + +
+ + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Параметры запуска</v8:content> + </v8:item> + + Vertical + Usual + NormalSeparation + + + + ФайлКонфигурации + false + true + true + true + + + + ФайлКонфигурацииПриИзменении + ФайлКонфигурацииНачалоВыбора + + + + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Отчет по результатам тестирования</v8:content> + </v8:item> + + Vertical + Usual + Use + + + + ОтобразитьОтчет + Auto + + + + + ФорматОтчета + Tumbler + + + + + ИмяФайлаОтчета + false + true + true + + + + ИмяФайлаОтчетаНачалоВыбора + + + + + + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Группа параметры запуска строка1</v8:content> + </v8:item> + + Horizontal + Usual + None + false + + + + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Логирование</v8:content> + </v8:item> + + Vertical + Usual + Use + + + + УровеньЛога + true + + + + + ИмяФайлаЛога + false + false + true + true + + + + ВыводЛогаНачалоВыбора + + + + ЛогированиеВКонсоль + Auto + + + + + + + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Прочее</v8:content> + </v8:item> + + Vertical + Usual + + + + ЗакрытьПослеТестирования + Auto + + + + + ИмяФайлаКодаВозврата + + + ru + В файл будет записан статус тестирования. 0 - тестирование завершилось успешно, отличное от 0 - были ошибки. + + + ShowBottom + false + true + true + + + + ИмяФайлаКодаВозвратаНачалоВыбора + + + + + + + + Usual + None + false + + + + ЗапускИзКонфигуратор + None + Tumbler + + + ru + БЛ='Строка запуска предприятия'; БИ='Запуск из конфигуратора' + + + + + + ЗапускИзПредприятияПриИзменении + + + + ПараметрыЗапуска + None + false + + + + + + + +
+ + + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Дерево тестов</v8:content> + </v8:item> + + + v8:ValueTree + + + + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Представление</v8:content> + </v8:item> + + + xs:string + + 0 + Variable + + + + + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Идентификатор</v8:content> + </v8:item> + + + xs:string + + 0 + Variable + + + + + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Тип объекта</v8:content> + </v8:item> + + + xs:decimal + + 1 + 0 + Any + + + + + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Отметка</v8:content> + </v8:item> + + + xs:decimal + + 1 + 0 + Any + + + + + + + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Файл конфигурации запуска</v8:content> + </v8:item> + + + xs:string + + 0 + Variable + + + + ФайлКонфигурации + + + + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Параметры запуска</v8:content> + </v8:item> + + + xs:string + + 0 + Variable + + + + + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Запуск из конифгуратор</v8:content> + </v8:item> + + + xs:boolean + + + ЗапускИзКонфигуратор + + + + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Логирование в файл</v8:content> + </v8:item> + + + xs:string + + 0 + Variable + + + + ИмяФайлаЛога + + + + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Показать отчет после выполнения тестов</v8:content> + </v8:item> + + + xs:boolean + + + ОтобразитьОтчет + + + + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Код возврата</v8:content> + </v8:item> + + + xs:string + + 0 + Variable + + + + ИмяФайлаКодаВозврата + + + + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Сохранить отчет в</v8:content> + </v8:item> + + + xs:string + + 0 + Variable + + + + ИмяФайлаОтчета + + + + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Логирование в консоль</v8:content> + </v8:item> + + + xs:boolean + + + + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Формат отчета</v8:content> + </v8:item> + + + xs:string + + 0 + Variable + + + + + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Уровень лога</v8:content> + </v8:item> + + + xs:string + + 0 + Variable + + + + + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Закрыть 1С:Предприятие по окончанию тестирования</v8:content> + </v8:item> + + + xs:boolean + + + + + + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Установить флажки</v8:content> + </v8:item> + + + StdPicture.CheckAll + true + + УстановитьФлажки + DontUse + + + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Снять флажки</v8:content> + </v8:item> + + + StdPicture.UncheckAll + true + + СнятьФлажки + DontUse + + + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Сохранить параметры</v8:content> + </v8:item> + + СохранитьПараметры + DontUse + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/DataProcessors/ЮТЮнитТесты/Forms/СозданиеНастройки/Ext/Form/Module.bsl b/src/cfe/YAXUnit/DataProcessors/ЮТЮнитТесты/Forms/СозданиеНастройки/Ext/Form/Module.bsl new file mode 100644 index 0000000..8cdbd97 --- /dev/null +++ b/src/cfe/YAXUnit/DataProcessors/ЮТЮнитТесты/Forms/СозданиеНастройки/Ext/Form/Module.bsl @@ -0,0 +1,587 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область ОписаниеПеременных +&НаКлиенте +Перем ПоддерживаемыеФорматыОтчетов; +#КонецОбласти + +#Область ОбработчикиСобытийФормы + +&НаСервере +Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка) + + Для Каждого УровеньЛог Из ЮТЛогирование.УровниЛога() Цикл + Элементы.УровеньЛога.СписокВыбора.Добавить(УровеньЛог.Значение, УровеньЛог.Ключ); + КонецЦикла; + + Конфигурация = ЮТФабрика.ПараметрыЗапуска(); + ФорматОтчета = Конфигурация.reportFormat; + УровеньЛога = Конфигурация.logging.level; + ОтобразитьОтчет = Конфигурация.showReport; + ЗакрытьПослеТестирования = Конфигурация.closeAfterTests; + ЛогированиеВКонсоль = Конфигурация.logging.console ; + +КонецПроцедуры + +&НаКлиенте +Процедура ПриОткрытии(Отказ) + + ЗаполнитьДеревоТестов(); + + ПоддерживаемыеФорматыОтчетов = ЮТОтчетСлужебный.ПоддерживаемыеФорматыОтчетов(); + Для Каждого Формат Из ПоддерживаемыеФорматыОтчетов Цикл + Элементы.ФорматОтчета.СписокВыбора.Добавить(Формат.Ключ, Формат.Значение.Представление); + КонецЦикла; + +КонецПроцедуры + +#КонецОбласти + +#Область ОбработчикиСобытийЭлементовШапкиФормы + +&НаКлиенте +Процедура ФайлКонфигурацииНачалоВыбора(Элемент, ДанныеВыбора, СтандартнаяОбработка) + + ВыбратьФайл("*.json|*.json", ФайлКонфигурации, Новый ОписаниеОповещения("УстановитьФайлКонфигурации", ЭтотОбъект)); + +КонецПроцедуры + +&НаКлиенте +Процедура ЗапускИзПредприятияПриИзменении(Элемент) + + ОбновитьСтрокуЗапуска(); + +КонецПроцедуры + +&НаКлиенте +Процедура ФайлКонфигурацииПриИзменении(Элемент) + + ОбновитьСтрокуЗапуска(); + +КонецПроцедуры + +&НаКлиенте +Процедура ВыводЛогаНачалоВыбора(Элемент, ДанныеВыбора, СтандартнаяОбработка) + + ВыбратьФайл("*.log|*.log|*.txt|*.txt|All files(*.*)|*.*", ИмяФайлаЛога, Новый ОписаниеОповещения("УстановитьИмяФайлаЛога", ЭтотОбъект)); + +КонецПроцедуры + +&НаКлиенте +Процедура ИмяФайлаКодаВозвратаНачалоВыбора(Элемент, ДанныеВыбора, СтандартнаяОбработка) + + ВыбратьФайл("All files(*.*)|*.*", ИмяФайлаЛога, Новый ОписаниеОповещения("УстановитьИмяФайлаКодаВозврата", ЭтотОбъект)); + +КонецПроцедуры + +&НаКлиенте +Процедура ИмяФайлаОтчетаНачалоВыбора(Элемент, ДанныеВыбора, СтандартнаяОбработка) + + ОписаниеФормата = Неопределено; + Если НЕ ПоддерживаемыеФорматыОтчетов.Свойство(ФорматОтчета, ОписаниеФормата) Тогда + ПоказатьПредупреждение(, "Сначала укажите формат отчета"); + Возврат; + КонецЕсли; + + Если ОписаниеФормата.ЗаписьВКаталог Тогда + ВыбратьКаталог(ИмяФайлаОтчета, Новый ОписаниеОповещения("УстановитьИмяФайлаОтчета", ЭтотОбъект)); + Иначе + ВыбратьФайл(ОписаниеФормата.ФильтрВыбораФайла, ИмяФайлаОтчета, Новый ОписаниеОповещения("УстановитьИмяФайлаОтчета", ЭтотОбъект)); + КонецЕсли; + +КонецПроцедуры + +#КонецОбласти + +#Область ОбработчикиСобытийЭлементовТаблицыФормыДеревоТестов + +&НаКлиенте +Процедура ДеревоТестовОтметкаПриИзменении(Элемент) + + Данные = Элементы.ДеревоТестов.ТекущиеДанные; + + Если Данные.Отметка = 2 Тогда + Данные.Отметка = 0; + КонецЕсли; + + УстановитьРекурсивноЗначение(Данные.ПолучитьЭлементы(), Данные.Отметка); + ОбновитьОтметкиРодителей(Данные); + +КонецПроцедуры + +#КонецОбласти + +#Область ОбработчикиКомандФормы + +&НаКлиенте +Процедура СнятьФлажки(Команда) + + УстановитьРекурсивноЗначение(ДеревоТестов.ПолучитьЭлементы(), 0); + +КонецПроцедуры + +&НаКлиенте +Процедура УстановитьФлажки(Команда) + + УстановитьРекурсивноЗначение(ДеревоТестов.ПолучитьЭлементы(), 1); + +КонецПроцедуры + +&НаКлиенте +Процедура СохранитьПараметры(Команда) + + Если НЕ ЕстьОтмеченныеТесты() Тогда + ПоказатьПредупреждение(, "Отметьте тесты, которые должны выполниться"); + Возврат; + КонецЕсли; + + Если ПустаяСтрока(ФайлКонфигурации) Тогда + Обработчик = Новый ОписаниеОповещения("СохранитьПараметрыПослеВыбораФайла", ЭтотОбъект); + ВыбратьФайл("*.json|*.json", ФайлКонфигурации, Обработчик); + Иначе + СохранитьПараметрыПослеВыбораФайла(ФайлКонфигурации); + КонецЕсли; + +КонецПроцедуры + +#КонецОбласти + +#Область СлужебныеПроцедурыИФункции + +&НаКлиенте +Процедура ЗаполнитьДеревоТестов() + + ЮТКонтекстСлужебный.ИнициализироватьКонтекст(); + ТестовыеМодули = ЮТЧитательСлужебный.ЗагрузитьТесты(Новый Структура("filter", Новый Структура)); + ЮТКонтекстСлужебный.УдалитьКонтекст(); + + СтрокиРасширений = Новый Соответствие(); + + Для Каждого ОписаниеМодуля Из ТестовыеМодули Цикл + + ИмяРасширения = ОписаниеМодуля.МетаданныеМодуля.Расширение; + + СтрокаРасширения = СтрокиРасширений[ИмяРасширения]; + Если СтрокаРасширения = Неопределено Тогда + СтрокаРасширения = ДобавитьСтрокуРасширения(ДеревоТестов, ИмяРасширения); + СтрокиРасширений.Вставить(ИмяРасширения, СтрокаРасширения); + КонецЕсли; + + СтрокаМодуля = ДобавитьСтрокуМодуля(СтрокаРасширения, ОписаниеМодуля.МетаданныеМодуля); + + Если ОписаниеМодуля.НаборыТестов.Количество() = 1 Тогда + + Для Каждого Тест Из ОписаниеМодуля.НаборыТестов[0].Тесты Цикл + + ДобавитьСтрокуТеста(СтрокаМодуля, Тест); + + КонецЦикла; + + Иначе + + Для Каждого Набор Из ОписаниеМодуля.НаборыТестов Цикл + + СтрокаНабора = ДобавитьСтрокуНабора(СтрокаМодуля, Набор); + + Для Каждого Тест Из Набор.Тесты Цикл + + ДобавитьСтрокуТеста(СтрокаНабора, Тест); + + КонецЦикла; + + КонецЦикла; + + КонецЕсли; + + КонецЦикла; + +КонецПроцедуры + +&НаКлиентеНаСервереБезКонтекста +Функция ДобавитьСтрокуРасширения(Владелец, ИмяРасширения) + + Строка = Владелец.ПолучитьЭлементы().Добавить(); + Строка.Идентификатор = ИмяРасширения; + Строка.Представление = ИмяРасширения; + Строка.ТипОбъекта = 0; + + Возврат Строка; + +КонецФункции + +&НаКлиентеНаСервереБезКонтекста +Функция ДобавитьСтрокуМодуля(Владелец, МетаданныеМодуля) + + Строка = Владелец.ПолучитьЭлементы().Добавить(); + Строка.Идентификатор = МетаданныеМодуля.Имя; + Строка.Представление = МетаданныеМодуля.Имя; + Строка.ТипОбъекта = 1; + + Возврат Строка; + +КонецФункции + +&НаКлиентеНаСервереБезКонтекста +Функция ДобавитьСтрокуНабора(Владелец, Набор) + + Строка = Владелец.ПолучитьЭлементы().Добавить(); + Строка.Идентификатор = Набор.Имя; + Строка.Представление = Набор.Представление; + Строка.ТипОбъекта = 2; + + Возврат Строка; + +КонецФункции + +&НаКлиентеНаСервереБезКонтекста +Функция ДобавитьСтрокуТеста(Владелец, Тест) + + Представление = ЮТФабрикаСлужебный.ПредставлениеТеста(Тест); + + Если Владелец.ТипОбъекта = 1 Тогда + СтрокаМодуля = Владелец; + Иначе + СтрокаМодуля = Владелец.ПолучитьРодителя(); + КонецЕсли; + + Строка = Владелец.ПолучитьЭлементы().Добавить(); + Строка.Идентификатор = СтрШаблон("%1.%2", СтрокаМодуля.Идентификатор, Тест.Имя); + Строка.Представление = СтрШаблон("%1, %2", Представление, СтрСоединить(Тест.КонтекстВызова, ", ")); + Строка.ТипОбъекта = 3; + + Возврат Строка; + +КонецФункции + +&НаКлиентеНаСервереБезКонтекста +Процедура УстановитьРекурсивноЗначение(Элементы, Значение, Колонка = "Отметка") + + Для Каждого Элемент Из Элементы Цикл + + Элемент[Колонка] = Значение; + + Если ЗначениеЗаполнено(Элемент.ПолучитьЭлементы()) Тогда + УстановитьРекурсивноЗначение(Элемент.ПолучитьЭлементы(), Значение, Колонка); + КонецЕсли; + + КонецЦикла; + +КонецПроцедуры + +&НаКлиентеНаСервереБезКонтекста +Процедура ОбновитьОтметкиРодителей(Элемент) + + Родитель = Элемент.ПолучитьРодителя(); + + Если Родитель = Неопределено Тогда + Возврат; + КонецЕсли; + + ЕстьСОтметкой = Ложь; + ЕстьБезОтметки = Ложь; + + Для Каждого Элемент Из Родитель.ПолучитьЭлементы() Цикл + + Если Элемент.Отметка = 0 Тогда + ЕстьБезОтметки = Истина; + ИначеЕсли Элемент.Отметка = 1 Тогда + ЕстьСОтметкой = Истина; + ИначеЕсли Элемент.Отметка = 2 Тогда + ЕстьБезОтметки = Истина; + ЕстьСОтметкой = Истина; + КонецЕсли; + + Если ЕстьБезОтметки И ЕстьСОтметкой Тогда + Прервать; + КонецЕсли; + + КонецЦикла; + + Если ЕстьСОтметкой И ЕстьБезОтметки Тогда + НоваяОтметка = 2; + ИначеЕсли ЕстьСОтметкой Тогда + НоваяОтметка = 1; + Иначе + НоваяОтметка = 0; + КонецЕсли; + + Если Родитель.Отметка = НоваяОтметка Тогда + Возврат; + КонецЕсли; + + Родитель.Отметка = НоваяОтметка; + ОбновитьОтметкиРодителей(Родитель); + +КонецПроцедуры + +&НаКлиенте +Процедура ОбновитьСтрокуЗапуска() + + ПараметрыЗапускаЮнитТестов = СтрШаблон("%1=%2", ЮТПараметрыЗапускаСлужебный.КлючЗапуска(), ФайлКонфигурации); + + Если ЗапускИзКонфигуратор Тогда + + ПараметрыЗапуска = ПараметрыЗапускаЮнитТестов; + + Иначе + +#Если ВебКлиент Тогда + ВызватьИсключение "Формирование строки запуска для веб-клиенте не поддерживается"; +#Иначе + СистемнаяИнформация = Новый СистемнаяИнформация; +#Если ТонкийКлиент Тогда + Файл = "1cv8c"; +#Иначе + Файл = "1cv8"; +#КонецЕсли + ПутьЗапускаемогоКлиента = ЮТФайлы.ОбъединитьПути(КаталогПрограммы(), Файл); + + Если СистемнаяИнформация.ТипПлатформы = ТипПлатформы.Windows_x86 Или СистемнаяИнформация.ТипПлатформы = ТипПлатформы.Windows_x86_64 Тогда + ПутьЗапускаемогоКлиента = ПутьЗапускаемогоКлиента + ".exe"; + КонецЕсли; + + Если ЗначениеЗаполнено(ИмяПользователя()) Тогда + Пользователь = СтрШаблон("/N""%1""", ИмяПользователя()); + Иначе + Пользователь = ""; + КонецЕсли; + + ПараметрыЗапуска = СтрШаблон("""%1"" %2 /IBConnectionString ""%3"" /C""%4""", + ПутьЗапускаемогоКлиента, + Пользователь, + СтрЗаменить(СтрокаСоединенияИнформационнойБазы(), """", """"""), + ПараметрыЗапускаЮнитТестов); +#КонецЕсли + + КонецЕсли; + +КонецПроцедуры + +&НаКлиенте +Процедура СохранитьПараметрыПослеВыбораФайла(ВыбранныйФайл, ДополнительныеПараметры = Неопределено) Экспорт + + ФайлКонфигурации = ВыбранныйФайл; + ОбновитьСтрокуЗапуска(); + СохранитьКонфигурациюЗапуска(); + +КонецПроцедуры + +&НаКлиенте +Процедура УстановитьФайлКонфигурации(ВыбранныйФайл, ДополнительныеПараметры) Экспорт + + Если ВыбранныйФайл <> Неопределено Тогда + ФайлКонфигурации = ВыбранныйФайл; + ОбновитьСтрокуЗапуска(); + КонецЕсли; + +КонецПроцедуры + +&НаКлиенте +Процедура УстановитьИмяФайлаЛога(ВыбранныйФайл, ДополнительныеПараметры) Экспорт + + Если ВыбранныйФайл <> Неопределено Тогда + ИмяФайлаЛога = ВыбранныйФайл; + КонецЕсли; + +КонецПроцедуры + +&НаКлиенте +Процедура УстановитьИмяФайлаКодаВозврата(ВыбранныйФайл, ДополнительныеПараметры) Экспорт + + Если ВыбранныйФайл <> Неопределено Тогда + ИмяФайлаКодаВозврата = ВыбранныйФайл; + КонецЕсли; + +КонецПроцедуры + +&НаКлиенте +Процедура УстановитьИмяФайлаОтчета(ВыбранныйФайл, ДополнительныеПараметры) Экспорт + + Если ВыбранныйФайл <> Неопределено Тогда + ИмяФайлаОтчета = ВыбранныйФайл; + КонецЕсли; + +КонецПроцедуры + +&НаКлиенте +Процедура ВыбратьФайл(Фильтр, ИмяФайла, Оповещение) + + ДиалогВыбораФайла = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Сохранение); + ДиалогВыбораФайла.Фильтр = Фильтр; + ДиалогВыбораФайла.МножественныйВыбор = Ложь; + ДиалогВыбораФайла.ПолноеИмяФайла = ИмяФайла; + + ПараметрыОбработчика = Новый Структура("Оповещение", Оповещение); + Обработчик = Новый ОписаниеОповещения("ПослеВыбораФайла", ЭтотОбъект, ПараметрыОбработчика); + ДиалогВыбораФайла.Показать(Обработчик); + +КонецПроцедуры + +&НаКлиенте +Процедура ВыбратьКаталог(ИмяФайла, Оповещение) + + ДиалогВыбораФайла = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.ВыборКаталога); + ДиалогВыбораФайла.МножественныйВыбор = Ложь; + ДиалогВыбораФайла.ПолноеИмяФайла = ИмяФайла; + + ПараметрыОбработчика = Новый Структура("Оповещение", Оповещение); + Обработчик = Новый ОписаниеОповещения("ПослеВыбораФайла", ЭтотОбъект, ПараметрыОбработчика); + ДиалогВыбораФайла.Показать(Обработчик); + +КонецПроцедуры + +&НаКлиенте +Процедура ПослеВыбораФайла(ВыбранныеФайлы, ДополнительныеПараметры) Экспорт + + Если ВыбранныеФайлы <> Неопределено Тогда + ВыполнитьОбработкуОповещения(ДополнительныеПараметры.Оповещение, ВыбранныеФайлы[0]); + КонецЕсли; + +КонецПроцедуры + +&НаКлиенте +Процедура СохранитьКонфигурациюЗапуска() + +#Если ВебКлиент Тогда + ВызватьИсключение "Сохранение конфигурации из веб-клиента не поддерживается"; +#Иначе + Конфигурация = ЮТФабрика.ПараметрыЗапуска(); + Конфигурация.Удалить("ВыполнятьМодульноеТестирование"); + + Конфигурация.showReport = ОтобразитьОтчет; + Конфигурация.closeAfterTests = ЗакрытьПослеТестирования; + Конфигурация.reportFormat = ФорматОтчета; + Конфигурация.reportPath = ИмяФайлаОтчета; + + Конфигурация.logging.level = УровеньЛога; + Конфигурация.logging.file = ИмяФайлаЛога; + Конфигурация.logging.console = ЛогированиеВКонсоль; + + Если ЗначениеЗаполнено(ИмяФайлаКодаВозврата) Тогда + Конфигурация.exitCode = ИмяФайлаКодаВозврата; + КонецЕсли; + + Если НЕ (УстановленФильтрПоРасширению(Конфигурация) ИЛИ УстановленФильтрПоМодулям(Конфигурация)) Тогда + УстановитьФильтрПоТестам(Конфигурация); + КонецЕсли; + + Запись = Новый ЗаписьJSON(); + СимволыОтступа = " "; + ПараметрыЗаписи = Новый ПараметрыЗаписиJSON(, СимволыОтступа); + Запись.ОткрытьФайл(ФайлКонфигурации, , , ПараметрыЗаписи); + ЗаписатьJSON(Запись, Конфигурация); + Запись.Закрыть(); +#КонецЕсли + +КонецПроцедуры + +&НаКлиенте +Функция ЕстьОтмеченныеТесты() + + Для Каждого СтрокаРасширения Из ДеревоТестов.ПолучитьЭлементы() Цикл + Если СтрокаРасширения.Отметка > 0 Тогда + Возврат Истина; + КонецЕсли; + КонецЦикла; + + Возврат Ложь; + +КонецФункции + +&НаКлиенте +Функция УстановленФильтрПоРасширению(Конфигурация) + + Расширения = Новый Массив(); + Для Каждого СтрокаРасширения Из ДеревоТестов.ПолучитьЭлементы() Цикл + + Если СтрокаРасширения.Отметка = 2 Тогда + Возврат Ложь; + ИначеЕсли СтрокаРасширения.Отметка = 1 Тогда + Расширения.Добавить(СтрокаРасширения.Идентификатор); + КонецЕсли; + + КонецЦикла; + + Если Расширения.Количество() Тогда + Конфигурация.filter.extensions = Расширения; + КонецЕсли; + + Возврат Расширения.Количество() > 0; + +КонецФункции + +&НаКлиенте +Функция УстановленФильтрПоМодулям(Конфигурация) + + Модули = Новый Массив(); + + Для Каждого СтрокаРасширения Из ДеревоТестов.ПолучитьЭлементы() Цикл + + Если СтрокаРасширения.Отметка = 0 Тогда + Продолжить; + КонецЕсли; + + Для Каждого СтрокаМодуля Из СтрокаРасширения.ПолучитьЭлементы() Цикл + + Если СтрокаМодуля.Отметка = 2 Тогда + Возврат Ложь; + ИначеЕсли СтрокаМодуля.Отметка = 1 Тогда + Модули.Добавить(СтрокаМодуля.Идентификатор); + КонецЕсли; + + КонецЦикла; + + КонецЦикла; + + Если Модули.Количество() Тогда + Конфигурация.filter.modules = Модули; + КонецЕсли; + + Возврат Модули.Количество() > 0; + +КонецФункции + +&НаКлиенте +Процедура УстановитьФильтрПоТестам(Конфигурация) + + Тесты = Новый Массив(); + ДобавитьОтмеченныеТесты(ДеревоТестов.ПолучитьЭлементы(), Тесты); + + Конфигурация.filter.tests = Тесты; + +КонецПроцедуры + +&НаКлиенте +Процедура ДобавитьОтмеченныеТесты(Строки, Тесты) + + Для Каждого Строка Из Строки Цикл + Если Строка.Отметка = 0 Тогда + Продолжить; + КонецЕсли; + + Если Строка.ТипОбъекта = 3 Тогда + Тесты.Добавить(Строка.Идентификатор); + Иначе + ДобавитьОтмеченныеТесты(Строка.ПолучитьЭлементы(), Тесты); + КонецЕсли; + КонецЦикла; + +КонецПроцедуры + +#КонецОбласти diff --git a/src/cfe/YAXUnit/DataProcessors/ЮТЮнитТесты/Forms/Сравнение.xml b/src/cfe/YAXUnit/DataProcessors/ЮТЮнитТесты/Forms/Сравнение.xml new file mode 100644 index 0000000..f4802f0 --- /dev/null +++ b/src/cfe/YAXUnit/DataProcessors/ЮТЮнитТесты/Forms/Сравнение.xml @@ -0,0 +1,22 @@ + + +
+ + Сравнение + + + ru + Сравнение + + + + Managed + false + + PlatformApplication + MobilePlatformApplication + + + +
+
\ No newline at end of file diff --git a/src/cfe/YAXUnit/DataProcessors/ЮТЮнитТесты/Forms/Сравнение/Ext/Form.xml b/src/cfe/YAXUnit/DataProcessors/ЮТЮнитТесты/Forms/Сравнение/Ext/Form.xml new file mode 100644 index 0000000..f699737 --- /dev/null +++ b/src/cfe/YAXUnit/DataProcessors/ЮТЮнитТесты/Forms/Сравнение/Ext/Form.xml @@ -0,0 +1,38 @@ + +
+ None + false + + + ПриСозданииНаСервере + + + + Скрипт + true + None + false + false + style:FormBackColor + + + + + + + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Скрипт</v8:content> + </v8:item> + + + xs:string + + 0 + Variable + + + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/DataProcessors/ЮТЮнитТесты/Forms/Сравнение/Ext/Form/Module.bsl b/src/cfe/YAXUnit/DataProcessors/ЮТЮнитТесты/Forms/Сравнение/Ext/Form/Module.bsl new file mode 100644 index 0000000..42bd74c --- /dev/null +++ b/src/cfe/YAXUnit/DataProcessors/ЮТЮнитТесты/Forms/Сравнение/Ext/Form/Module.bsl @@ -0,0 +1,34 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2023 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область ОбработчикиСобытийФормы + +&НаСервере +Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка) + + ТекстСтраницы = Обработки.ЮТЮнитТесты.ПолучитьМакет("СравнениеOld").ПолучитьТекст(); + + ТекстСтраницы = СтрЗаменить(ТекстСтраницы, "ИсходныйТекст", Параметры.ОжидаемоеЗначение); + ТекстСтраницы = СтрЗаменить(ТекстСтраницы, "СравниваемыйТекст", Параметры.ФактическоеЗначение); + + АдресСтраницы = ПоместитьВоВременноеХранилище(ПолучитьДвоичныеДанныеИзСтроки(ТекстСтраницы), УникальныйИдентификатор); + Скрипт = СтрШаблон("%1/%2", ПолучитьНавигационнуюСсылкуИнформационнойБазы(), АдресСтраницы); + +КонецПроцедуры + +#КонецОбласти diff --git a/src/cfe/YAXUnit/DataProcessors/ЮТЮнитТесты/Templates/Сравнение.xml b/src/cfe/YAXUnit/DataProcessors/ЮТЮнитТесты/Templates/Сравнение.xml new file mode 100644 index 0000000..8e530f2 --- /dev/null +++ b/src/cfe/YAXUnit/DataProcessors/ЮТЮнитТесты/Templates/Сравнение.xml @@ -0,0 +1,16 @@ + + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/DataProcessors/ЮТЮнитТесты/Templates/Сравнение/Ext/Template.txt b/src/cfe/YAXUnit/DataProcessors/ЮТЮнитТесты/Templates/Сравнение/Ext/Template.txt new file mode 100644 index 0000000..3a3d0e4 --- /dev/null +++ b/src/cfe/YAXUnit/DataProcessors/ЮТЮнитТесты/Templates/Сравнение/Ext/Template.txt @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + +
+ + \ No newline at end of file diff --git a/src/cfe/YAXUnit/DataProcessors/ЮТЮнитТесты/Templates/СравнениеOld.xml b/src/cfe/YAXUnit/DataProcessors/ЮТЮнитТесты/Templates/СравнениеOld.xml new file mode 100644 index 0000000..dc425c1 --- /dev/null +++ b/src/cfe/YAXUnit/DataProcessors/ЮТЮнитТесты/Templates/СравнениеOld.xml @@ -0,0 +1,16 @@ + + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/DataProcessors/ЮТЮнитТесты/Templates/СравнениеOld/Ext/Template.txt b/src/cfe/YAXUnit/DataProcessors/ЮТЮнитТесты/Templates/СравнениеOld/Ext/Template.txt new file mode 100644 index 0000000..8f5e360 --- /dev/null +++ b/src/cfe/YAXUnit/DataProcessors/ЮТЮнитТесты/Templates/СравнениеOld/Ext/Template.txt @@ -0,0 +1,936 @@ + + + + + + + + Diff test + + + + + + + +
+
+

Edit

+
+
+
+
+

Ожидаемое значение

+
+
+

+    
+
+
+

Фактическое значение

+
+
+

+    
+ + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/Ext/ManagedApplicationModule.bsl b/src/cfe/YAXUnit/Ext/ManagedApplicationModule.bsl new file mode 100644 index 0000000..874afc7 --- /dev/null +++ b/src/cfe/YAXUnit/Ext/ManagedApplicationModule.bsl @@ -0,0 +1,50 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область ОписаниеПеременных + +Перем ЮТДанныеКонтекста Экспорт; + +#КонецОбласти + +///////////////////////////////////////////////////////////////////////////////// +// Обработчики событий модуля +///////////////////////////////////////////////////////////////////////////////// +#Область ОбработчикиСобытий + +///////////////////////////////////////////////////////////////////////////////// +// ОТКРЫТИЕ ПРИЛОЖЕНИЯ +///////////////////////////////////////////////////////////////////////////////// + +// Используется для перехвата управления расширением после отработки запуска приложения +//@skip-check not-allowed-pragma +&После("ПриНачалеРаботыСистемы") +Процедура ЮТПриНачалеРаботыСистемы() + + ПодключитьОбработчикОжидания("ЮТВыполнитьМодульноеТестирование", 0.1, Истина); + +КонецПроцедуры + +&After("OnStart") +Procedure ЮТOnStart() + + ЮТИсполнительСлужебныйКлиент.ВыполнитьМодульноеТестирование(); + +EndProcedure + +#КонецОбласти diff --git a/src/cfe/YAXUnit/Ext/OrdinaryApplicationModule.bsl b/src/cfe/YAXUnit/Ext/OrdinaryApplicationModule.bsl new file mode 100644 index 0000000..ef0acd4 --- /dev/null +++ b/src/cfe/YAXUnit/Ext/OrdinaryApplicationModule.bsl @@ -0,0 +1,43 @@ +//©///////////////////////////////////////////////////////////////////////////©// +// +// Copyright 2021-2024 BIA-Technologies Limited Liability Company +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//©///////////////////////////////////////////////////////////////////////////©// + +#Область ОписаниеПеременных + +Перем ЮТДанныеКонтекста Экспорт; + +#КонецОбласти + +///////////////////////////////////////////////////////////////////////////////// +// Обработчики событий модуля +///////////////////////////////////////////////////////////////////////////////// +#Область ОбработчикиСобытий + +///////////////////////////////////////////////////////////////////////////////// +// ОТКРЫТИЕ ПРИЛОЖЕНИЯ +///////////////////////////////////////////////////////////////////////////////// + +// Используется для перехвата управления расширением после отработки запуска приложения +//@skip-check not-allowed-pragma +&После("ПриНачалеРаботыСистемы") +Процедура ЮТПриНачалеРаботыСистемы() + + ЮТИсполнительСлужебныйКлиент.ВыполнитьМодульноеТестирование(); + +КонецПроцедуры + +#КонецОбласти diff --git a/src/cfe/YAXUnit/Languages/Русский.xml b/src/cfe/YAXUnit/Languages/Русский.xml new file mode 100644 index 0000000..fc81dfa --- /dev/null +++ b/src/cfe/YAXUnit/Languages/Русский.xml @@ -0,0 +1,12 @@ + + + + + + Adopted + Русский + + ru + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/Subsystems/ЮТДвижок.xml b/src/cfe/YAXUnit/Subsystems/ЮТДвижок.xml new file mode 100644 index 0000000..99e6302 --- /dev/null +++ b/src/cfe/YAXUnit/Subsystems/ЮТДвижок.xml @@ -0,0 +1,34 @@ + + + + + ЮТДвижок + + + ru + Юнит тесты + + + + true + false + false + + + ru + Внутренняя реализация инструмента + + + + + + + ЮТИсполнитель + ЮТКонтекст + ЮТМокирование + ЮТСервис + ЮТТестовыеДанные + ЮТУтверждения + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/Subsystems/ЮТДвижок/Subsystems/ЮТИсполнитель.xml b/src/cfe/YAXUnit/Subsystems/ЮТДвижок/Subsystems/ЮТИсполнитель.xml new file mode 100644 index 0000000..7b0a343 --- /dev/null +++ b/src/cfe/YAXUnit/Subsystems/ЮТДвижок/Subsystems/ЮТИсполнитель.xml @@ -0,0 +1,37 @@ + + + + + ЮТИсполнитель + + + ru + Исполнитель + + + + true + false + false + + + ru + Функциональность запуска тестирования + + + + + CommonModule.ЮТИсполнительСлужебныйВызовСервера + CommonModule.ЮТИсполнительСлужебныйГлобальный + CommonModule.ЮТИсполнительСлужебныйКлиент + CommonModule.ЮТИсполнительСлужебныйКлиентСервер + CommonModule.ЮТПараметрыЗапускаСлужебный + CommonModule.ЮТТестыСлужебный + CommonModule.ЮТФильтрацияСлужебный + CommonModule.ЮТЧитательСлужебный + CommonModule.ЮТЧитательСлужебныйВызовСервера + + + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/Subsystems/ЮТДвижок/Subsystems/ЮТКонтекст.xml b/src/cfe/YAXUnit/Subsystems/ЮТДвижок/Subsystems/ЮТКонтекст.xml new file mode 100644 index 0000000..ae53460 --- /dev/null +++ b/src/cfe/YAXUnit/Subsystems/ЮТДвижок/Subsystems/ЮТКонтекст.xml @@ -0,0 +1,32 @@ + + + + + ЮТКонтекст + + + ru + Контекст + + + + true + false + false + + + ru + Функциональность работы с контекстами + + + + + CommonModule.ЮТКонтекстСлужебный + CommonModule.ЮТКонтекстСлужебныйВызовСервера + CommonModule.ЮТКонтекстСлужебныйКлиент + CommonModule.ЮТКонтекстТеста + + + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/Subsystems/ЮТДвижок/Subsystems/ЮТМокирование.xml b/src/cfe/YAXUnit/Subsystems/ЮТДвижок/Subsystems/ЮТМокирование.xml new file mode 100644 index 0000000..be6a93e --- /dev/null +++ b/src/cfe/YAXUnit/Subsystems/ЮТДвижок/Subsystems/ЮТМокирование.xml @@ -0,0 +1,34 @@ + + + + + ЮТМокирование + + + ru + Мокирование + + + + true + false + false + + + ru + Содержит функциональности мокирования данных + + + + + CommonModule.МокитоОбучение + CommonModule.МокитоПроверки + CommonModule.МокитоСлужебный + DataProcessor.ЮТHTTPServiceRequest + DataProcessor.ЮТHTTPСервисЗапрос + DataProcessor.ЮТRecordSet + + + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/Subsystems/ЮТДвижок/Subsystems/ЮТСервис.xml b/src/cfe/YAXUnit/Subsystems/ЮТДвижок/Subsystems/ЮТСервис.xml new file mode 100644 index 0000000..d755f66 --- /dev/null +++ b/src/cfe/YAXUnit/Subsystems/ЮТДвижок/Subsystems/ЮТСервис.xml @@ -0,0 +1,59 @@ + + + + + ЮТСервис + + + ru + Сервис + + + + true + false + false + + + ru + Сервисная функциональность работы движка + + + + + CommonModule.ЮТАсинхроннаяОбработкаСлужебныйКлиент + CommonModule.ЮТИсключения + CommonModule.ЮТКомпоненты + CommonModule.ЮТКомпонентыСлужебныйВызовСервера + CommonModule.ЮТКомпонентыСлужебныйКлиент + CommonModule.ЮТЛогированиеСлужебныйВызовСервера + CommonModule.ЮТЛокальСлужебный + CommonModule.ЮТМетаданныеСлужебныйВызовСервера + CommonModule.ЮТМетаданныеСлужебныйПовтИсп + CommonModule.ЮТНастройкиВыполнения + CommonModule.ЮТОбщийСлужебныйВызовСервера + CommonModule.ЮТОтчетСлужебный + CommonModule.ЮТПроверкиСлужебный + CommonModule.ЮТРасширенияСлужебный + CommonModule.ЮТРегистрацияОшибокСлужебный + CommonModule.ЮТСлужебныйПовторногоИспользования + CommonModule.ЮТСобытияСлужебный + CommonModule.ЮТСообщенияСлужебный + CommonModule.ЮТТипыДанныхСлужебный + CommonModule.ЮТФабрикаСлужебный + CommonModule.ЮТФайлы + CommonPicture.ЮТНеизвестный + CommonPicture.ЮТОшибка + CommonPicture.ЮТПодсистема + CommonPicture.ЮТПропущен + CommonPicture.ЮТУпал + CommonPicture.ЮТУспешно + CommonPicture.ЮТЭлементыТестов + CommonTemplate.ЮТRegEx1CAddin + CommonTemplate.ЮТYaxUnitAddIn + CommonTemplate.ЮТОписаниеМетаданных + + + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/Subsystems/ЮТДвижок/Subsystems/ЮТТестовыеДанные.xml b/src/cfe/YAXUnit/Subsystems/ЮТДвижок/Subsystems/ЮТТестовыеДанные.xml new file mode 100644 index 0000000..31ab28e --- /dev/null +++ b/src/cfe/YAXUnit/Subsystems/ЮТДвижок/Subsystems/ЮТТестовыеДанные.xml @@ -0,0 +1,39 @@ + + + + + ЮТТестовыеДанные + + + ru + Тестовые данные + + + + true + false + false + + + ru + Реализация генерации и работы с тестовыми данными + + + + + CommonModule.ЮТКонструкторВариантов + CommonModule.ЮТКонструкторТестовыхДанныхСлужебный + CommonModule.ЮТПреобразованияСлужебный + CommonModule.ЮТСтроки + CommonModule.ЮТТестовыеДанные + CommonModule.ЮТТестовыеДанныеСлужебный + CommonModule.ЮТТестовыеДанныеСлужебныйВызовСервера + CommonModule.ЮТТестовыеДанныеСлужебныйТаблицыЗначений + DataProcessor.ЮТКонструкторТестовыхДанных + + + + ЮТПодражатель + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/Subsystems/ЮТДвижок/Subsystems/ЮТТестовыеДанные/Subsystems/ЮТПодражатель.xml b/src/cfe/YAXUnit/Subsystems/ЮТДвижок/Subsystems/ЮТТестовыеДанные/Subsystems/ЮТПодражатель.xml new file mode 100644 index 0000000..04a3ba2 --- /dev/null +++ b/src/cfe/YAXUnit/Subsystems/ЮТДвижок/Subsystems/ЮТТестовыеДанные/Subsystems/ЮТПодражатель.xml @@ -0,0 +1,38 @@ + + + + + ЮТПодражатель + + + ru + Подражатель + + + + true + false + false + + + + CommonModule.ЮТПодражатель + CommonModule.ЮТПодражатель_Банки + CommonModule.ЮТПодражатель_Компании + CommonModule.ЮТПодражатель_Люди + CommonModule.ЮТПодражательСлужебный + CommonModule.ЮТПодражательСлужебныйВызовСервера + CommonModule.ЮТПодражательСлужебныйПовтИсп + CommonTemplate.ЮТ_СловарьПодражателя_Компании_Наименования_ru + CommonTemplate.ЮТ_СловарьПодражателя_Компании_ПрефиксыНаименований_ru + CommonTemplate.ЮТ_СловарьПодражателя_Люди_ЖенскиеИмена_ru + CommonTemplate.ЮТ_СловарьПодражателя_Люди_ЖенскиеОтчества_ru + CommonTemplate.ЮТ_СловарьПодражателя_Люди_ЖенскиеФамилии_ru + CommonTemplate.ЮТ_СловарьПодражателя_Люди_МужскиеИмена_ru + CommonTemplate.ЮТ_СловарьПодражателя_Люди_МужскиеОтчества_ru + CommonTemplate.ЮТ_СловарьПодражателя_Люди_МужскиеФамилии_ru + + + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/Subsystems/ЮТДвижок/Subsystems/ЮТУтверждения.xml b/src/cfe/YAXUnit/Subsystems/ЮТДвижок/Subsystems/ЮТУтверждения.xml new file mode 100644 index 0000000..a012d05 --- /dev/null +++ b/src/cfe/YAXUnit/Subsystems/ЮТДвижок/Subsystems/ЮТУтверждения.xml @@ -0,0 +1,36 @@ + + + + + ЮТУтверждения + + + ru + Утверждения + + + + true + false + false + + + ru + Реализация утверждений для проверки результатов при тестировании + + + + + CommonModule.ЮТЗапросыСлужебныйВызовСервера + CommonModule.ЮТЗапросыСлужебныйКлиентСервер + CommonModule.ЮТПредикаты + CommonModule.ЮТПредикатыСлужебныйКлиентСервер + CommonModule.ЮТСравнениеСлужебныйВызовСервера + CommonModule.ЮТСравнениеСлужебныйКлиентСервер + CommonModule.ЮТУтверждения + CommonModule.ЮТУтвержденияИБ + + + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/Subsystems/ЮТДинамическиПодключаемые.xml b/src/cfe/YAXUnit/Subsystems/ЮТДинамическиПодключаемые.xml new file mode 100644 index 0000000..ea00f2c --- /dev/null +++ b/src/cfe/YAXUnit/Subsystems/ЮТДинамическиПодключаемые.xml @@ -0,0 +1,30 @@ + + + + + ЮТДинамическиПодключаемые + + + ru + Динамически подключаемые + + + + true + false + false + + + ru + Содержит подсистемы с динамически подключаемой (загружаемой) функциональностью + + + + + + + ЮТОбработчикиСобытий + ЮТФормированиеОтчета + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/Subsystems/ЮТДинамическиПодключаемые/Subsystems/ЮТОбработчикиСобытий.xml b/src/cfe/YAXUnit/Subsystems/ЮТДинамическиПодключаемые/Subsystems/ЮТОбработчикиСобытий.xml new file mode 100644 index 0000000..0930391 --- /dev/null +++ b/src/cfe/YAXUnit/Subsystems/ЮТДинамическиПодключаемые/Subsystems/ЮТОбработчикиСобытий.xml @@ -0,0 +1,33 @@ + + + + + ЮТОбработчикиСобытий + + + ru + Обработчики событий + + + + true + false + false + + + ru + Подключаемые обработчики событий тестов + + + + + CommonModule.МокитоСлужебный + CommonModule.ЮТИсполнительСлужебныйКлиент + CommonModule.ЮТЛогированиеСлужебный + CommonModule.ЮТТестовыеДанныеСлужебный + CommonModule.ЮТУтверждения + + + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/Subsystems/ЮТДинамическиПодключаемые/Subsystems/ЮТФормированиеОтчета.xml b/src/cfe/YAXUnit/Subsystems/ЮТДинамическиПодключаемые/Subsystems/ЮТФормированиеОтчета.xml new file mode 100644 index 0000000..c12ba88 --- /dev/null +++ b/src/cfe/YAXUnit/Subsystems/ЮТДинамическиПодключаемые/Subsystems/ЮТФормированиеОтчета.xml @@ -0,0 +1,31 @@ + + + + + ЮТФормированиеОтчета + + + ru + Формирование отчета + + + + true + false + false + + + ru + Функциональность формирования отчетов + + + + + CommonModule.ЮТОтчетAllureСлужебный + CommonModule.ЮТОтчетJSONСлужебный + CommonModule.ЮТОтчетJUnitСлужебный + + + + + \ No newline at end of file diff --git a/src/cfe/YAXUnit/Subsystems/ЮТПубличный.xml b/src/cfe/YAXUnit/Subsystems/ЮТПубличный.xml new file mode 100644 index 0000000..1f0403d --- /dev/null +++ b/src/cfe/YAXUnit/Subsystems/ЮТПубличный.xml @@ -0,0 +1,62 @@ + + + + + ЮТПубличный + + + ru + YAxUnit + + + + true + true + false + + + ru + Публичные API и инструменты, применяемые при написании тестов и самом тестировании. Остальные использовать напрямую не рекомендуется + + + + CommonPicture.ЮТПодсистема + false + + + CommonModule.Мокито + CommonModule.МокитоОбучение + CommonModule.МокитоПроверки + CommonModule.ЮТест + CommonModule.ЮТЗапросы + CommonModule.ЮТИсключения + CommonModule.ЮТКоллекции + CommonModule.ЮТКомпоненты + CommonModule.ЮТКонструкторВариантов + CommonModule.ЮТКонтекстТеста + CommonModule.ЮТЛогирование + CommonModule.ЮТМетаданные + CommonModule.ЮТНастройкиВыполнения + CommonModule.ЮТОбщий + CommonModule.ЮТПодражатель + CommonModule.ЮТПодражатель_Банки + CommonModule.ЮТПодражатель_Компании + CommonModule.ЮТПодражатель_Люди + CommonModule.ЮТПредикаты + CommonModule.ЮТСтроки + CommonModule.ЮТТестовыеДанные + CommonModule.ЮТТесты + CommonModule.ЮТУтверждения + CommonModule.ЮТУтвержденияИБ + CommonModule.ЮТФабрика + CommonModule.ЮТФайлы + DataProcessor.ЮТHTTPServiceRequest + DataProcessor.ЮТHTTPСервисЗапрос + DataProcessor.ЮТRecordSet + DataProcessor.ЮТКонструкторТестовыхДанных + DataProcessor.ЮТЮнитТесты + + + + + \ No newline at end of file diff --git a/tools/VBParams.json b/tools/VBParams.json index 6096686..6d796ce 100644 --- a/tools/VBParams.json +++ b/tools/VBParams.json @@ -4,9 +4,9 @@ "ВыполнитьСценарии": true, "ЗавершитьРаботуСистемы": true, "ЗакрытьTestClientПослеЗапускаСценариев": true, - "КаталогФич": "$workspaceRoot/feature/core", + "КаталогФич": "$workspaceRoot/features", "КаталогиБиблиотек": [ - "$workspaceRoot/feature/lib" + "$workspaceRoot/features" ], "СписокТеговИсключение": [ "IgnoreOnCIMainBuild", @@ -56,7 +56,7 @@ "ПрикладыватьКОтчетуAllureДанныеОСостоянииВсехФорм": true, "ПрикладыватьКОтчетуAllureДанныеОСетевыхСоединениях": false, "ПрикладыватьКОтчетуAllureДанныеОПроцессахОС": false, - "КаталогОтносительноКоторогоНадоСтроитьИерархию": "$workspaceRoot/features/core", + "КаталогОтносительноКоторогоНадоСтроитьИерархию": "$workspaceRoot/features", "ДанныеАллюрМеток": [] }, "ДелатьОтчетВФорматеjUnit": false, diff --git a/tools/yaxunit.json b/tools/yaxunit.json new file mode 100644 index 0000000..b591045 --- /dev/null +++ b/tools/yaxunit.json @@ -0,0 +1,26 @@ +{ + "reportPath": "./build/out/yaxunit/junit.xml", + "closeAfterTests": true, + "filter": { + "extensions": [ + "YAXUNIT" + ], + "modules": null, + "suites": null, + "tags": null, + "contexts": null, + "paths": null, + "tests": null + }, + "settings": { + "ВТранзакции": true + }, + "reportFormat": "jUnit", + "showReport": false, + "logging": { + "file": "./build/out/yaxunit/log.txt", + "enable": false, + "level": "debug" + }, + "exitCode": "./build/out/yaxunit/result.txt" +} \ No newline at end of file