diff --git "a/docs/product/\320\272\320\276\320\274\320\260\320\275\320\264\321\213/30-epf.md" "b/docs/product/\320\272\320\276\320\274\320\260\320\275\320\264\321\213/30-epf.md" index dee3b812..f23407d5 100644 --- "a/docs/product/\320\272\320\276\320\274\320\260\320\275\320\264\321\213/30-epf.md" +++ "b/docs/product/\320\272\320\276\320\274\320\260\320\275\320\264\321\213/30-epf.md" @@ -72,7 +72,12 @@ vrunner epf convert --src ./build/xml ./build/edt ## compile -Собирает внешние обработки (`.epf`/`.erf`) из XML-исходников. Поддерживает обработку целого каталога с рекурсивным поиском. +Собирает внешние обработки (`.epf`) и внешние отчёты (`.erf`) из XML-исходников. +Поддерживает обработку целого каталога с рекурсивным поиском. + +Тип объекта определяется по корневому тегу XML, он же задаёт расширение результата: +`ExternalDataProcessor` → `.epf`, `ExternalReport` → `.erf`. В одном дереве исходников +обработки и отчёты могут лежать вперемешку — каждый объект соберётся со своим расширением. ```bash vrunner epf compile [опции] [SRC] @@ -82,14 +87,14 @@ vrunner epf compile [опции] [SRC] | Аргумент | Описание | |----------|----------| -| `SRC` | Каталог с XML-исходниками обработок (по умолчанию - текущий каталог) | +| `SRC` | Каталог с XML-исходниками обработок и отчётов (по умолчанию - текущий каталог) | ### Опции | Опция | Переменная окружения | Описание | |-------|---------------------|----------| -| `--R`, `--recursive` | - | Рекурсивный поиск обработок в подкаталогах | -| `--out` | - | Каталог для сохранения собранных обработок | +| `--R`, `--recursive` | - | Рекурсивный поиск обработок и отчётов в подкаталогах | +| `--out` | - | Каталог для сохранения собранных обработок и отчётов | | `--ibconnection` | `VRUNNER_IBCONNECTION` | Строка подключения к ИБ. Если не указана - автоматически создаётся временная ИБ | | `--db-user` | `VRUNNER_DBUSER` | Пользователь информационной базы | | `--db-pwd` | `VRUNNER_DBPWD` | Пароль пользователя ИБ | @@ -111,8 +116,8 @@ vrunner epf compile [опции] [SRC] ::: tip Исходники 1С:EDT Если `SRC` — проект внешних объектов 1С:EDT (`--src-format edt` или автоопределение), -`compile` сначала выгружает его в XML через `1cedtcli` (`export`), затем собирает `.epf` -из полученных XML. Требуется установленная 1С:EDT. +`compile` сначала выгружает его в XML через `1cedtcli` (`export`), затем собирает +`.epf`/`.erf` из полученных XML. Требуется установленная 1С:EDT. ::: ### Примеры @@ -137,7 +142,8 @@ vrunner epf compile \ ## decompile -Разбирает файл обработки `.epf`/`.erf` (или каталог с файлами) в XML-исходники. +Разбирает файл внешней обработки `.epf` или внешнего отчёта `.erf` (либо каталог с такими +файлами) в XML-исходники. При обходе каталога подхватываются оба расширения. ```bash vrunner epf decompile [опции] @@ -147,13 +153,13 @@ vrunner epf decompile [опции] | Аргумент | Описание | |----------|----------| -| `SRC` | Путь к EPF-файлу или каталогу с EPF-файлами (**обязательный**) | +| `SRC` | Путь к EPF/ERF-файлу или каталогу с ними (**обязательный**) | ### Опции | Опция | Переменная окружения | Описание | |-------|---------------------|----------| -| `--R`, `--recursive` | - | Рекурсивный поиск EPF-файлов (для каталога) | +| `--R`, `--recursive` | - | Рекурсивный поиск EPF/ERF-файлов (для каталога) | | `--out` | - | Каталог для сохранения разобранных исходников | | `--ibconnection` | `VRUNNER_IBCONNECTION` | Строка подключения к ИБ. Если не указана - автоматически создаётся временная ИБ | | `--db-user` | `VRUNNER_DBUSER` | Пользователь информационной базы | diff --git "a/src/cli/Epf_\320\237\320\276\320\264\320\272\320\276\320\274\320\260\320\275\320\264\321\213/\320\237\320\276\320\264\320\272\320\276\320\274\320\260\320\275\320\264\320\260EpfCompile.os" "b/src/cli/Epf_\320\237\320\276\320\264\320\272\320\276\320\274\320\260\320\275\320\264\321\213/\320\237\320\276\320\264\320\272\320\276\320\274\320\260\320\275\320\264\320\260EpfCompile.os" index 06249683..35c7645d 100644 --- "a/src/cli/Epf_\320\237\320\276\320\264\320\272\320\276\320\274\320\260\320\275\320\264\321\213/\320\237\320\276\320\264\320\272\320\276\320\274\320\260\320\275\320\264\320\260EpfCompile.os" +++ "b/src/cli/Epf_\320\237\320\276\320\264\320\272\320\276\320\274\320\260\320\275\320\264\321\213/\320\237\320\276\320\264\320\272\320\276\320\274\320\260\320\275\320\264\320\260EpfCompile.os" @@ -24,15 +24,15 @@ &НаборОпций("НаборОпцийСУБД") Перем ОпцииСУБД; -&Аргумент(Имя = "SRC", Описание = "Каталог с исходниками обработки (по умолчанию - текущий)") +&Аргумент(Имя = "SRC", Описание = "Каталог с исходниками обработки или отчёта (по умолчанию - текущий)") &ТСтрока Перем КаталогИсходников; -&Опция(Имя = "R recursive", Описание = "Рекурсивный поиск обработок") +&Опция(Имя = "R recursive", Описание = "Рекурсивный поиск обработок и отчётов") &Флаговый Перем Рекурсивно; -&Опция(Имя = "out", Описание = "Каталог для сохранения собранных обработок") +&Опция(Имя = "out", Описание = "Каталог для сохранения собранных обработок и отчётов") &ТСтрока Перем КаталогВыгрузки; @@ -42,7 +42,8 @@ &НаборОпций("НаборОпцийНастроек") Перем ОпцииНастроек; // BSLLS:UnusedLocalVariable-off -&ПодкомандаПриложения(Имя = "compile", Родитель = "КомандаEpf", Описание = "Собрать внешние обработки из исходников") +&ПодкомандаПриложения(Имя = "compile", Родитель = "КомандаEpf", + Описание = "Собрать внешние обработки и отчёты из исходников") &ДоступноВMCP &MCPДлительная Процедура ПриСозданииОбъекта() diff --git "a/src/cli/Epf_\320\237\320\276\320\264\320\272\320\276\320\274\320\260\320\275\320\264\321\213/\320\237\320\276\320\264\320\272\320\276\320\274\320\260\320\275\320\264\320\260EpfDecompile.os" "b/src/cli/Epf_\320\237\320\276\320\264\320\272\320\276\320\274\320\260\320\275\320\264\321\213/\320\237\320\276\320\264\320\272\320\276\320\274\320\260\320\275\320\264\320\260EpfDecompile.os" index 4618528c..5b323f24 100644 --- "a/src/cli/Epf_\320\237\320\276\320\264\320\272\320\276\320\274\320\260\320\275\320\264\321\213/\320\237\320\276\320\264\320\272\320\276\320\274\320\260\320\275\320\264\320\260EpfDecompile.os" +++ "b/src/cli/Epf_\320\237\320\276\320\264\320\272\320\276\320\274\320\260\320\275\320\264\321\213/\320\237\320\276\320\264\320\272\320\276\320\274\320\260\320\275\320\264\320\260EpfDecompile.os" @@ -21,12 +21,12 @@ &НаборОпций("НаборОпцийСУБД") Перем ОпцииСУБД; -&Аргумент(Имя = "SRC", Описание = "Путь к файлу обработки (.epf) или каталогу с обработками") +&Аргумент(Имя = "SRC", Описание = "Путь к файлу обработки или отчёта (.epf/.erf) или каталогу с ними") &ТСтрока &Обязательный Перем Источник; -&Опция(Имя = "R recursive", Описание = "Рекурсивный поиск EPF-файлов (для каталога)") +&Опция(Имя = "R recursive", Описание = "Рекурсивный поиск EPF/ERF-файлов (для каталога)") &Флаговый Перем Рекурсивно; @@ -40,7 +40,8 @@ &НаборОпций("НаборОпцийНастроек") Перем ОпцииНастроек; // BSLLS:UnusedLocalVariable-off -&ПодкомандаПриложения(Имя = "decompile", Родитель = "КомандаEpf", Описание = "Разобрать внешние обработки в исходники") +&ПодкомандаПриложения(Имя = "decompile", Родитель = "КомандаEpf", + Описание = "Разобрать внешние обработки и отчёты в исходники") &ДоступноВMCP &MCPДлительная Процедура ПриСозданииОбъекта() diff --git "a/src/core/\320\224\320\262\320\270\320\266\320\272\320\270/\320\232\320\273\320\260\321\201\321\201\321\213/\320\224\320\262\320\270\320\266\320\276\320\272Ibcmd.os" "b/src/core/\320\224\320\262\320\270\320\266\320\272\320\270/\320\232\320\273\320\260\321\201\321\201\321\213/\320\224\320\262\320\270\320\266\320\276\320\272Ibcmd.os" index 6398a235..1296c797 100644 --- "a/src/core/\320\224\320\262\320\270\320\266\320\272\320\270/\320\232\320\273\320\260\321\201\321\201\321\213/\320\224\320\262\320\270\320\266\320\276\320\272Ibcmd.os" +++ "b/src/core/\320\224\320\262\320\270\320\266\320\272\320\270/\320\232\320\273\320\260\321\201\321\201\321\213/\320\224\320\262\320\270\320\266\320\276\320\272Ibcmd.os" @@ -59,6 +59,7 @@ Процедура ЗагрузитьКонфигурациюИзФайлов(Знач ПараметрыПодключения, Знач КаталогИсходников, Знач ПараметрыПлатформы = Неопределено, Знач СписокФайлов = "") Экспорт + КаталогИсходников = АбсолютныйПуть(КаталогИсходников); Лог.Отладка("Загрузка конфигурации из файлов через ibcmd: %1", КаталогИсходников); Менеджер = СоздатьМенеджер(ПараметрыПлатформы); УстановитьКонтекстИБ(Менеджер, ПараметрыПодключения); @@ -110,6 +111,7 @@ Возврат Результат; КонецЕсли; + ПутьКФайлуВерсийДляСравнения = АбсолютныйПуть(ПутьКФайлуВерсийДляСравнения); Лог.Отладка("Инкрементальная загрузка: сравниваем конфигурацию с кешем ConfigDumpInfo через ibcmd: %1", ПутьКФайлуВерсийДляСравнения); ПутьКФайлуИзменений = ПолучитьИмяВременногоФайла(".txt"); @@ -158,6 +160,7 @@ Процедура ЗагрузитьКонфигурациюИзФайла(Знач ПараметрыПодключения, Знач ПутьКФайлуCf, Знач ПараметрыПлатформы = Неопределено) Экспорт + ПутьКФайлуCf = АбсолютныйПуть(ПутьКФайлуCf); Лог.Отладка("Загрузка конфигурации из файла через ibcmd: %1", ПутьКФайлуCf); Менеджер = СоздатьМенеджер(ПараметрыПлатформы); УстановитьКонтекстИБ(Менеджер, ПараметрыПодключения); @@ -176,6 +179,7 @@ Процедура ВыгрузитьКонфигурациюВФайл(Знач ПараметрыПодключения, Знач ПутьКФайлуCf, Знач ПараметрыПлатформы = Неопределено) Экспорт + ПутьКФайлуCf = АбсолютныйПуть(ПутьКФайлуCf); Лог.Отладка("Выгрузка конфигурации в файл через ibcmd: %1", ПутьКФайлуCf); ОбеспечитьКаталогДляФайла(ПутьКФайлуCf); Менеджер = СоздатьМенеджер(ПараметрыПлатформы); @@ -239,6 +243,7 @@ Процедура ЗагрузитьИнфобазуИзФайла(Знач ПараметрыПодключения, Знач ПутьКФайлуDT, // BSLLS:Typo-off Знач ПараметрыПлатформы = Неопределено) Экспорт + ПутьКФайлуDT = АбсолютныйПуть(ПутьКФайлуDT); Лог.Отладка("Загрузка инфобазы из файла DT: %1", ПутьКФайлуDT); // BSLLS:Typo-off Менеджер = СоздатьМенеджер(ПараметрыПлатформы); УстановитьКонтекстИБ(Менеджер, ПараметрыПодключения); @@ -256,6 +261,7 @@ Процедура ВыгрузитьИнфобазуВФайл(Знач ПараметрыПодключения, Знач ПутьКФайлуDT, // BSLLS:Typo-off Знач ПараметрыПлатформы = Неопределено) Экспорт + ПутьКФайлуDT = АбсолютныйПуть(ПутьКФайлуDT); Лог.Отладка("Выгрузка инфобазы в файл DT: %1", ПутьКФайлуDT); // BSLLS:Typo-off ОбеспечитьКаталогДляФайла(ПутьКФайлуDT); Менеджер = СоздатьМенеджер(ПараметрыПлатформы); @@ -321,6 +327,7 @@ Процедура ЗагрузитьРасширениеИзФайла(Знач ПараметрыПодключения, Знач ПутьКФайлуCfe, Знач ИмяРасширения, Знач ПараметрыПлатформы = Неопределено) Экспорт + ПутьКФайлуCfe = АбсолютныйПуть(ПутьКФайлуCfe); Лог.Отладка("Загрузка расширения через ibcmd: %1 (имя=%2)", ПутьКФайлуCfe, ИмяРасширения); Менеджер = СоздатьМенеджер(ПараметрыПлатформы); УстановитьКонтекстИБ(Менеджер, ПараметрыПодключения); @@ -340,6 +347,7 @@ Процедура ВыгрузитьРасширениеВФайл(Знач ПараметрыПодключения, Знач ПутьКФайлуCfe, Знач ИмяРасширения, Знач ПараметрыПлатформы = Неопределено) Экспорт + ПутьКФайлуCfe = АбсолютныйПуть(ПутьКФайлуCfe); Лог.Отладка("Выгрузка расширения через ibcmd: %1 (имя=%2)", ПутьКФайлуCfe, ИмяРасширения); ОбеспечитьКаталогДляФайла(ПутьКФайлуCfe); Менеджер = СоздатьМенеджер(ПараметрыПлатформы); @@ -361,6 +369,7 @@ Процедура ЗагрузитьРасширениеИзФайлов(Знач ПараметрыПодключения, Знач КаталогИсходников, Знач ИмяРасширения, Знач ПараметрыПлатформы = Неопределено, Знач СписокФайлов = "") Экспорт + КаталогИсходников = АбсолютныйПуть(КаталогИсходников); Лог.Отладка("Загрузка расширения из файлов через ibcmd: %1 (имя=%2)", КаталогИсходников, ИмяРасширения); Менеджер = СоздатьМенеджер(ПараметрыПлатформы); УстановитьКонтекстИБ(Менеджер, ПараметрыПодключения); @@ -669,6 +678,19 @@ КонецПроцедуры +// Привести путь к абсолютному перед передачей в ibcmd. +// +// ibcmd некорректно разбирает относительные пути с префиксом "./" или ".\": корневой каталог +// он открывает, а вложенные файлы ищет уже относительно другого каталога и падает с +// "Операция невозможна: файл <путь> отсутствует либо поврежден" - причём на разных файлах +// от запуска к запуску. Абсолютный путь снимает неоднозначность. +// +// Параметры: +// Путь - Строка - путь к файлу или каталогу (может быть относительным) +// +// Возвращаемое значение: +// Строка - абсолютный путь; пустая строка, если путь не задан +// Функция АбсолютныйПуть(Знач Путь) Файл = Новый Файл(Путь); Возврат Файл.ПолноеИмя; diff --git "a/src/core/\320\241\320\265\321\200\320\262\320\270\321\201\321\213/\320\232\320\273\320\260\321\201\321\201\321\213/\320\241\320\265\321\200\320\262\320\270\321\201\320\236\320\261\321\200\320\260\320\261\320\276\321\202\320\276\320\272.os" "b/src/core/\320\241\320\265\321\200\320\262\320\270\321\201\321\213/\320\232\320\273\320\260\321\201\321\201\321\213/\320\241\320\265\321\200\320\262\320\270\321\201\320\236\320\261\321\200\320\260\320\261\320\276\321\202\320\276\320\272.os" index 39e73978..60d61de6 100644 --- "a/src/core/\320\241\320\265\321\200\320\262\320\270\321\201\321\213/\320\232\320\273\320\260\321\201\321\201\321\213/\320\241\320\265\321\200\320\262\320\270\321\201\320\236\320\261\321\200\320\260\320\261\320\276\321\202\320\276\320\272.os" +++ "b/src/core/\320\241\320\265\321\200\320\262\320\270\321\201\321\213/\320\232\320\273\320\260\321\201\321\201\321\213/\320\241\320\265\321\200\320\262\320\270\321\201\320\236\320\261\321\200\320\260\320\261\320\276\321\202\320\276\320\272.os" @@ -2,10 +2,12 @@ // BSLLS:NumberOfOptionalParams-off (&Лог/&Пластилин/&Напильник) и внутреннее состояние сервиса. // BSLLS:MissingParameterDescription-off Внутренний проброс ПараметрыИсходников. // BSLLS:MissingTemporaryFileDeletion-off Временный XML удаляется через УдалитьВременныйКаталог. -// Сервис операций с внешними обработками (EPF). -// Фасад: поиск XML-исходников, валидация, компиляция и разборка EPF. +// Сервис операций с внешними обработками (EPF) и внешними отчётами (ERF). +// Фасад: поиск XML-исходников, валидация, компиляция и разборка EPF/ERF. +// Тип объекта определяется по корневому тегу XML (ExternalDataProcessor/ExternalReport) +// и задаёт расширение результата сборки: .epf для обработок, .erf для отчётов. // Оркестрирует создание/очистку временных баз и вызовы ДвижокКонфигуратор. -// EPF-операции всегда выполняются через конфигуратор. +// EPF/ERF-операции всегда выполняются через конфигуратор. // Флаг ibcmd влияет только на способ создания временной базы. &Лог("vrunner") @@ -23,11 +25,11 @@ #Область ПрограммныйИнтерфейс -// Собрать внешнюю обработку из XML-исходников. +// Собрать внешнюю обработку или отчёт из XML-исходников. // // Параметры: -// КаталогИсходников - Строка - каталог с XML-исходниками обработки -// КаталогВыгрузки - Строка - каталог для EPF-файла (по умолчанию рядом с XML) +// КаталогИсходников - Строка - каталог с XML-исходниками обработки или отчёта +// КаталогВыгрузки - Строка - каталог для EPF/ERF-файла (по умолчанию рядом с XML) // ИспользоватьIbcmd - Булево - использовать ibcmd для создания временной базы // ПараметрыПлатформы - Структура, Неопределено - версия платформы и путь к ней // ПараметрыПодключения - Структура, Неопределено - параметры ИБ (для готовой базы) @@ -42,14 +44,18 @@ Возврат; КонецЕсли; - ФайлXml = НайтиФайлОбработки(КаталогИсходников); - Если ФайлXml = Неопределено Тогда - ВызватьИсключение СтрШаблон("В каталоге %1 не найден XML-файл внешней обработки (ExternalDataProcessor)", + ВнешниеОбъекты = НайтиВнешниеОбъекты(КаталогИсходников, Ложь); + Если ВнешниеОбъекты.Количество() = 0 Тогда + ВызватьИсключение СтрШаблон( + "В каталоге %1 не найден XML-файл внешней обработки или отчёта (ExternalDataProcessor/ExternalReport)", КаталогИсходников); КонецЕсли; + ВнешнийОбъект = ВнешниеОбъекты[0]; + ФайлXml = ВнешнийОбъект.ФайлXml; ИмяОбработки = ФайлXml.ИмяБезРасширения; - ПутьКФайлуEpf = ОпределитьПутьВыгрузкиEpf(КаталогИсходников, КаталогВыгрузки, ИмяОбработки); + ПутьКФайлуEpf = ОпределитьПутьВыгрузкиEpf( + КаталогИсходников, КаталогВыгрузки, ИмяОбработки, ВнешнийОбъект.Расширение); Лог.Информация("Сборка обработки: %1 → %2", ФайлXml.ПолноеИмя, ПутьКФайлуEpf); @@ -69,11 +75,11 @@ КонецПроцедуры -// Собрать все обработки из каталога (рекурсивный поиск). +// Собрать все обработки и отчёты из каталога (рекурсивный поиск). // // Параметры: // КаталогПоиска - Строка - каталог для рекурсивного поиска XML-исходников -// КаталогВыгрузки - Строка - каталог для EPF-файлов (по умолчанию рядом с XML) +// КаталогВыгрузки - Строка - каталог для EPF/ERF-файлов (по умолчанию рядом с XML) // ИспользоватьIbcmd - Булево - использовать ibcmd для создания временной базы // ПараметрыПлатформы - Структура, Неопределено - версия платформы и путь к ней // ПараметрыПодключения - Структура, Неопределено - параметры ИБ (для готовой базы) @@ -88,23 +94,26 @@ Возврат; КонецЕсли; - КаталогиОбработок = НайтиКаталогиОбработокРекурсивно(КаталогПоиска); + ВнешниеОбъекты = НайтиВнешниеОбъекты(КаталогПоиска, Истина); - Если КаталогиОбработок.Количество() = 0 Тогда - ВызватьИсключение СтрШаблон("В каталоге %1 не найдено XML-файлов внешних обработок (ExternalDataProcessor)", + Если ВнешниеОбъекты.Количество() = 0 Тогда + ВызватьИсключение СтрШаблон( + "В каталоге %1 не найдено XML-файлов внешних обработок и отчётов" + + " (ExternalDataProcessor/ExternalReport)", КаталогПоиска); КонецЕсли; - Лог.Информация("Найдено обработок для сборки: %1", КаталогиОбработок.Количество()); + Лог.Информация("Найдено обработок для сборки: %1", ВнешниеОбъекты.Количество()); КонтекстБазы = ПодготовитьБазу(ИспользоватьIbcmd, ПараметрыПодключения, ПараметрыПлатформы); Попытка Движок = Движки["ДвижокКонфигуратор"]; - Для Каждого КаталогОбработки Из КаталогиОбработок Цикл - ФайлXml = НайтиФайлОбработки(КаталогОбработки); + Для Каждого ВнешнийОбъект Из ВнешниеОбъекты Цикл + ФайлXml = ВнешнийОбъект.ФайлXml; ИмяОбработки = ФайлXml.ИмяБезРасширения; - ПутьКФайлуEpf = ОпределитьПутьВыгрузкиEpf(КаталогОбработки, КаталогВыгрузки, ИмяОбработки); + ПутьКФайлуEpf = ОпределитьПутьВыгрузкиEpf( + ФайлXml.Путь, КаталогВыгрузки, ИмяОбработки, ВнешнийОбъект.Расширение); Лог.Информация("Сборка обработки: %1 → %2", ФайлXml.ПолноеИмя, ПутьКФайлуEpf); Движок.СобратьВнешнююОбработкуИзФайлов( КонтекстБазы.ПараметрыПодключения, ФайлXml.ПолноеИмя, ПутьКФайлуEpf, ПараметрыПлатформы); @@ -119,10 +128,10 @@ КонецПроцедуры -// Разобрать EPF-файл в XML-исходники. +// Разобрать EPF/ERF-файл в XML-исходники. // // Параметры: -// ПутьКФайлуEpf - Строка - путь к EPF-файлу +// ПутьКФайлуEpf - Строка - путь к EPF/ERF-файлу // КаталогВыгрузки - Строка - каталог для XML-исходников (по умолчанию рядом с EPF) // ИспользоватьIbcmd - Булево - использовать ibcmd для создания временной базы // ПараметрыПлатформы - Структура, Неопределено - версия платформы и путь к ней @@ -163,10 +172,10 @@ КонецПроцедуры -// Разобрать все EPF-файлы из каталога. +// Разобрать все EPF/ERF-файлы из каталога. // // Параметры: -// КаталогПоиска - Строка - каталог поиска EPF-файлов +// КаталогПоиска - Строка - каталог поиска EPF/ERF-файлов // Рекурсивно - Булево - выполнять поиск рекурсивно // КаталогВыгрузки - Строка - каталог для XML-исходников (по умолчанию рядом с EPF) // ИспользоватьIbcmd - Булево - использовать ibcmd для создания временной базы @@ -177,10 +186,11 @@ Знач ИспользоватьIbcmd = Ложь, Знач ПараметрыПлатформы = Неопределено, Знач ПараметрыПодключения = Неопределено, Знач ПараметрыИсходников = Неопределено) Экспорт - ФайлыEpf = НайтиФайлы(КаталогПоиска, "*.epf", Рекурсивно); + ФайлыEpf = НайтиФайлыВнешнихОбъектов(КаталогПоиска, Рекурсивно); Если ФайлыEpf.Количество() = 0 Тогда - ВызватьИсключение СтрШаблон("В каталоге %1 не найдено файлов обработок (*.epf)", КаталогПоиска); + ВызватьИсключение СтрШаблон("В каталоге %1 не найдено файлов обработок и отчётов (*.epf, *.erf)", + КаталогПоиска); КонецЕсли; Лог.Информация("Найдено обработок для разборки: %1", ФайлыEpf.Количество()); @@ -244,9 +254,10 @@ #Область СлужебныеПроцедурыИФункции -// Собрать внешние обработки из EDT-проекта: выгрузить проект в XML через 1cedtcli -// (export), затем собрать каждый объект в .epf через одну временную базу. -// Раскладка выгрузки export (ExternalDataProcessors/<Имя>.xml) собирается по списку файлов. +// Собрать внешние обработки и отчёты из EDT-проекта: выгрузить проект в XML через 1cedtcli +// (export), затем собрать каждый объект в .epf/.erf через одну временную базу. +// Раскладка выгрузки export (ExternalDataProcessors/ и ExternalReports/<Имя>.xml) +// собирается по списку файлов. Процедура СобратьОбработкиИзEDT(Знач КаталогEDT, Знач КаталогВыгрузки, Знач ИспользоватьIbcmd, Знач ПараметрыПлатформы, Знач ПараметрыПодключения, Знач ПараметрыИсходников) @@ -262,7 +273,8 @@ Движок = Движки["ДвижокКонфигуратор"]; Для Каждого ФайлXml Из Файлы Цикл ИмяОбработки = ФайлXml.ИмяБезРасширения; - ПутьКФайлуEpf = ОпределитьПутьВыгрузкиEpf(ФайлXml.Путь, КаталогРезультата, ИмяОбработки); + ПутьКФайлуEpf = ОпределитьПутьВыгрузкиEpf( + ФайлXml.Путь, КаталогРезультата, ИмяОбработки, РасширениеОбъектаEDT(ФайлXml)); Лог.Информация("Сборка обработки: %1 → %2", ФайлXml.ПолноеИмя, ПутьКФайлуEpf); Движок.СобратьВнешнююОбработкуИзФайлов( КонтекстБазы.ПараметрыПодключения, ФайлXml.ПолноеИмя, ПутьКФайлуEpf, ПараметрыПлатформы); @@ -336,85 +348,124 @@ КонецФункции -// Найти XML-файл внешней обработки в каталоге. -// Ищет файл, содержащий тег ExternalDataProcessor. +// Найти XML-исходники внешних объектов (обработок и отчётов) в каталоге. // // Параметры: -// КаталогИсходников - Строка - каталог для поиска +// КаталогПоиска - Строка - каталог для поиска +// Рекурсивно - Булево - искать во вложенных каталогах // // Возвращаемое значение: -// Файл, Неопределено - найденный файл или Неопределено +// Массив из Структура - ФайлXml (Файл), Расширение (Строка: "epf"/"erf") // -Функция НайтиФайлОбработки(Знач КаталогИсходников) +Функция НайтиВнешниеОбъекты(Знач КаталогПоиска, Знач Рекурсивно) - ФайлыXml = НайтиФайлы(КаталогИсходников, "*.xml", Ложь); + Результат = Новый Массив; - Для Каждого ФайлXml Из ФайлыXml Цикл - Если СодержитТегОбработки(ФайлXml.ПолноеИмя) Тогда - Возврат ФайлXml; + Для Каждого ФайлXml Из НайтиФайлы(КаталогПоиска, "*.xml", Рекурсивно) Цикл + Расширение = РасширениеВнешнегоОбъекта(ФайлXml.ПолноеИмя); + Если НЕ ЗначениеЗаполнено(Расширение) Тогда + Продолжить; КонецЕсли; + Результат.Добавить(Новый Структура("ФайлXml, Расширение", ФайлXml, Расширение)); КонецЦикла; - Возврат Неопределено; + Возврат Результат; КонецФункции -// Рекурсивный поиск каталогов с XML-исходниками обработок. +// Найти файлы собранных внешних объектов (обработок и отчётов) в каталоге. // // Параметры: -// КорневойКаталог - Строка - каталог для поиска +// КаталогПоиска - Строка - каталог для поиска +// Рекурсивно - Булево - искать во вложенных каталогах // // Возвращаемое значение: -// Массив из Строка - пути к каталогам с обработками +// Массив из Файл - найденные EPF/ERF-файлы // -Функция НайтиКаталогиОбработокРекурсивно(Знач КорневойКаталог) +Функция НайтиФайлыВнешнихОбъектов(Знач КаталогПоиска, Знач Рекурсивно) Результат = Новый Массив; - ФайлыXml = НайтиФайлы(КорневойКаталог, "*.xml", Истина); - - Для Каждого ФайлXml Из ФайлыXml Цикл - Если СодержитТегОбработки(ФайлXml.ПолноеИмя) Тогда - Результат.Добавить(ФайлXml.Путь); - КонецЕсли; + Для Каждого Маска Из СтрРазделить("*.epf,*.erf", ",") Цикл + Для Каждого Файл Из НайтиФайлы(КаталогПоиска, Маска, Рекурсивно) Цикл + Результат.Добавить(Файл); + КонецЦикла; КонецЦикла; Возврат Результат; КонецФункции -// Проверить, содержит ли XML-файл тег ExternalDataProcessor. +// Определить тип внешнего объекта по корневому тегу XML. // // Параметры: // ПутьКФайлу - Строка - путь к XML-файлу // // Возвращаемое значение: -// Булево +// Строка - расширение результата сборки: "epf" (ExternalDataProcessor), +// "erf" (ExternalReport) или "" - если файл не является корневым XML внешнего объекта // -Функция СодержитТегОбработки(Знач ПутьКФайлу) +Функция РасширениеВнешнегоОбъекта(Знач ПутьКФайлу) ЧтениеТекста = Новый ЧтениеТекста(ПутьКФайлу); Содержимое = ЧтениеТекста.Прочитать(); ЧтениеТекста.Закрыть(); СодержимоеВРег = ВРег(Содержимое); // BSLLS:Typo-off - Возврат СтрНайти(СодержимоеВРег, " 1 И (Прав(Путь, 1) = "\" ИЛИ Прав(Путь, 1) = "/") Цикл + Путь = Лев(Путь, СтрДлина(Путь) - 1); + КонецЦикла; + + Возврат ?(ВРег(Новый Файл(Путь).Имя) = "EXTERNALREPORTS", "erf", "epf"); КонецФункции -// Определить путь к выходному EPF-файлу. +// Определить путь к выходному EPF/ERF-файлу. // // Параметры: // КаталогИсходников - Строка - каталог с исходниками // КаталогВыгрузки - Строка - каталог для выгрузки (может быть пустым) -// ИмяОбработки - Строка - имя обработки (без расширения) +// ИмяОбработки - Строка - имя обработки или отчёта (без расширения) +// Расширение - Строка - расширение результата сборки: "epf" или "erf" // // Возвращаемое значение: -// Строка - полный путь к EPF-файлу +// Строка - полный путь к EPF/ERF-файлу // -Функция ОпределитьПутьВыгрузкиEpf(Знач КаталогИсходников, Знач КаталогВыгрузки, Знач ИмяОбработки) +Функция ОпределитьПутьВыгрузкиEpf(Знач КаталогИсходников, Знач КаталогВыгрузки, Знач ИмяОбработки, Знач Расширение) - ИмяФайла = ИмяОбработки + ".epf"; + ИмяФайла = ИмяОбработки + "." + Расширение; Если ЗначениеЗаполнено(КаталогВыгрузки) Тогда ФайлКаталога = Новый Файл(КаталогВыгрузки); @@ -430,10 +481,10 @@ КонецФункции -// Определить каталог для разборки EPF. +// Определить каталог для разборки EPF/ERF. // // Параметры: -// ФайлEpf - Файл - файл обработки +// ФайлEpf - Файл - файл обработки или отчёта // КаталогВыгрузки - Строка - каталог для выгрузки (может быть пустым) // // Возвращаемое значение: @@ -451,7 +502,7 @@ Возврат ОбъединитьПути(КаталогВыгрузки, ИмяКаталога); КонецЕсли; - // Рядом с EPF-файлом + // Рядом с EPF/ERF-файлом Возврат ОбъединитьПути(ФайлEpf.Путь, ИмяКаталога); КонецФункции diff --git "a/tests/e2e/client-tests/epf/\320\242\320\265\321\201\321\202EpfCompile.os" "b/tests/e2e/client-tests/epf/\320\242\320\265\321\201\321\202EpfCompile.os" index d9c62012..e8143212 100644 --- "a/tests/e2e/client-tests/epf/\320\242\320\265\321\201\321\202EpfCompile.os" +++ "b/tests/e2e/client-tests/epf/\320\242\320\265\321\201\321\202EpfCompile.os" @@ -1,10 +1,11 @@ // BSLLS-off // Тестовый набор: epf compile -// Интеграционные тесты сборки внешних обработок из XML-исходников. +// Интеграционные тесты сборки внешних обработок и отчётов из XML-исходников. // // Тесты запускают реальную CLI-команду `vrunner epf compile` через подпроцесс. // -// Фикстуры: tests/e2e/fixtures/epf/ - XML-исходники обработок +// Фикстуры: tests/e2e/fixtures/epf/ - XML-исходники обработок (ExternalDataProcessor) +// и внешнего отчёта (ExternalReport, собирается в .erf) #Использовать asserts #Использовать tempfiles @@ -38,7 +39,32 @@ КонецПроцедуры -// Рекурсивная сборка обработок. +// Сборка внешнего отчёта из исходников: ExternalReport собирается в .erf, а не в .epf. +// Прогоняется дважды: с ibcmd и через конфигуратор. +&ПараметризованныйТест +&ИсточникЗначение("ibcmd") +&ИсточникЗначение("designer") +Процедура ТестДолжен_СобратьОтчетИзИсходников(Режим) Экспорт + + // Дано + Исполнитель = СоздатьИсполнителя(); + КаталогSrc = Исполнитель.ПутьФикстуры("epf", "ТестовыйОтчет"); + Исполнитель.ДобавитьОпцию("--out", Исполнитель.КаталогРаботы()); + ДобавитьФлагРежима(Исполнитель, Режим); + Исполнитель.ДобавитьАргумент(КаталогSrc); + + // Когда + Исполнитель.ВыполнитьКоманду(); + + // Тогда + Исполнитель.ОжидаемЧтоКодВозврата(0, "сборка внешнего отчёта из исходников"); + Исполнитель.ОжидаемЧтоФайлСуществует("ТестовыйОтчет.erf"); + Ожидаем.Что(Новый Файл(ОбъединитьПути(Исполнитель.КаталогРаботы(), "ТестовыйОтчет.epf")).Существует(), + "отчёт не должен собираться в .epf").ЭтоЛожь(); + +КонецПроцедуры + +// Рекурсивная сборка обработок и отчётов. // Прогоняется дважды: с ibcmd и через конфигуратор. &ПараметризованныйТест &ИсточникЗначение("ibcmd") @@ -60,6 +86,7 @@ Исполнитель.ОжидаемЧтоКодВозврата(0, "рекурсивная сборка обработок из каталога"); Исполнитель.ОжидаемЧтоФайлСуществует("ТестоваяОбработка.epf"); Исполнитель.ОжидаемЧтоФайлСуществует("ВтораяОбработка.epf"); + Исполнитель.ОжидаемЧтоФайлСуществует("ТестовыйОтчет.erf"); КонецПроцедуры diff --git "a/tests/e2e/client-tests/epf/\320\242\320\265\321\201\321\202EpfDecompile.os" "b/tests/e2e/client-tests/epf/\320\242\320\265\321\201\321\202EpfDecompile.os" index 61170d6b..fcd2aa3f 100644 --- "a/tests/e2e/client-tests/epf/\320\242\320\265\321\201\321\202EpfDecompile.os" +++ "b/tests/e2e/client-tests/epf/\320\242\320\265\321\201\321\202EpfDecompile.os" @@ -1,10 +1,11 @@ // BSLLS-off // Тестовый набор: epf decompile -// Интеграционные тесты разборки внешних обработок в XML-исходники. +// Интеграционные тесты разборки внешних обработок и отчётов в XML-исходники. // // Тесты запускают реальную CLI-команду `vrunner epf decompile` через подпроцесс. // -// Фикстуры: tests/e2e/fixtures/epf/ - XML-исходники обработок +// Фикстуры: tests/e2e/fixtures/epf/ - XML-исходники обработок (ExternalDataProcessor) +// и внешнего отчёта (ExternalReport, собирается в .erf) #Использовать asserts #Использовать tempfiles @@ -40,17 +41,41 @@ КонецПроцедуры -// Разборка обработок из каталога с рекурсивным поиском. +// Разборка внешнего отчёта (.erf) в исходники. +&Тест +Процедура ТестДолжен_РазобратьОтчетВИсходники() Экспорт + + // Дано: сначала собираем ERF из фикстуры + ПутьErf = СобратьОбработкуИзФикстуры("ТестовыйОтчет", "erf"); + + Исполнитель = СоздатьИсполнителя(); + Исполнитель.ДобавитьОпцию("--out", Исполнитель.КаталогРаботы()); + Исполнитель.ДобавитьАргумент(ПутьErf); + + // Когда + Исполнитель.ВыполнитьКоманду(); + + // Тогда + Исполнитель.ОжидаемЧтоКодВозврата(0, "разборка внешнего отчёта в исходники"); + Исполнитель.ОжидаемЧтоКаталогСуществует("ТестовыйОтчет"); + Ожидаем.Что( + Новый Файл(ОбъединитьПути(Исполнитель.КаталогРаботы(), "ТестовыйОтчет", "ТестовыйОтчет.xml")).Существует(), + "корневой XML отчёта выгружен").ЭтоИстина(); + +КонецПроцедуры + +// Разборка обработок и отчётов из каталога с рекурсивным поиском. // Прогоняется дважды: с ibcmd и через конфигуратор. &ПараметризованныйТест &ИсточникЗначение("ibcmd") &ИсточникЗначение("designer") Процедура ТестДолжен_РазобратьОбработкиИзКаталогаРекурсивно(Режим) Экспорт - // Дано: собираем обработки + // Дано: собираем обработки и внешний отчёт в один каталог КаталогEpf = ВременныеФайлы.СоздатьКаталог(); СобратьОбработкуВКаталог("ТестоваяОбработка", КаталогEpf); СобратьОбработкуВКаталог("ВтораяОбработка", КаталогEpf); + СобратьОбработкуВКаталог("ТестовыйОтчет", КаталогEpf); Исполнитель = СоздатьИсполнителя(); Исполнитель.ДобавитьФлаг("-R"); @@ -65,6 +90,7 @@ Исполнитель.ОжидаемЧтоКодВозврата(0, "рекурсивная разборка обработок из каталога"); Исполнитель.ОжидаемЧтоКаталогСуществует("ТестоваяОбработка"); Исполнитель.ОжидаемЧтоКаталогСуществует("ВтораяОбработка"); + Исполнитель.ОжидаемЧтоКаталогСуществует("ТестовыйОтчет"); КонецПроцедуры @@ -124,7 +150,7 @@ Возврат Новый ИсполнительCLI(Аргументы); КонецФункции -Функция СобратьОбработкуИзФикстуры(Знач ИмяОбработки) +Функция СобратьОбработкуИзФикстуры(Знач ИмяОбработки, Знач Расширение = "epf") ИсполнительСборки = СоздатьИсполнителяСборки(); КаталогSrc = ИсполнительСборки.ПутьФикстуры("epf", ИмяОбработки); @@ -133,7 +159,7 @@ ИсполнительСборки.ВыполнитьКоманду(); Ожидаем.Что(ИсполнительСборки.КодВозврата(), "Сборка фикстуры должна завершиться успешно").Равно(0); - Возврат ОбъединитьПути(ИсполнительСборки.КаталогРаботы(), ИмяОбработки + ".epf"); + Возврат ОбъединитьПути(ИсполнительСборки.КаталогРаботы(), ИмяОбработки + "." + Расширение); КонецФункции diff --git "a/tests/e2e/client-tests/infobase/\320\242\320\265\321\201\321\202InfobaseInit.os" "b/tests/e2e/client-tests/infobase/\320\242\320\265\321\201\321\202InfobaseInit.os" index 1ad83260..d39856f0 100644 --- "a/tests/e2e/client-tests/infobase/\320\242\320\265\321\201\321\202InfobaseInit.os" +++ "b/tests/e2e/client-tests/infobase/\320\242\320\265\321\201\321\202InfobaseInit.os" @@ -58,6 +58,29 @@ КонецПроцедуры +// Создание базы из исходников, заданных ОТНОСИТЕЛЬНЫМ путём с префиксом "./". +// Регрессия: ibcmd на таком пути открывает корневой каталог, но вложенные файлы ищет мимо +// и падает с "файл <путь> отсутствует либо поврежден" - каждый раз на другом файле. +&ПараметризованныйТест +&ИсточникЗначение("ibcmd") +&ИсточникЗначение("designer") +Процедура ТестДолжен_СоздатьБазуИзИсходников_ПоОтносительномуПути(Режим) Экспорт + + // Дано - фикстура материализуется в каталоге работы исполнителя, он же рабочий каталог команды + Исполнитель = СоздатьИсполнителя(); + Исполнитель.ПутьФикстуры("cf"); + Исполнитель.ДобавитьОпцию("--src", "./fixtures/cf"); + ДобавитьФлагРежима(Исполнитель, Режим); + + // Когда + Исполнитель.ВыполнитьКоманду(); + + // Тогда + Исполнитель.ОжидаемЧтоКодВозврата(0, "создание ИБ из исходников по относительному пути"); + Исполнитель.ОжидаемЧтоКаталогСуществует(ОбъединитьПути("build", "ib")); + +КонецПроцедуры + // Создание базы с загрузкой конфигурации из cf-файла. // Требуется cf-файл, сначала собираем его, потом создаём базу из него. &ПараметризованныйТест diff --git "a/tests/e2e/fixtures/epf/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\236\321\202\321\207\320\265\321\202/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\236\321\202\321\207\320\265\321\202.xml" "b/tests/e2e/fixtures/epf/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\236\321\202\321\207\320\265\321\202/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\236\321\202\321\207\320\265\321\202.xml" new file mode 100644 index 00000000..8d1edb42 --- /dev/null +++ "b/tests/e2e/fixtures/epf/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\236\321\202\321\207\320\265\321\202/\320\242\320\265\321\201\321\202\320\276\320\262\321\213\320\271\320\236\321\202\321\207\320\265\321\202.xml" @@ -0,0 +1,34 @@ + + + + + + e41aff26-25cf-4bb6-b6c1-3f478a75f374 + a7291ae7-d8da-44bf-bf4e-32486b2f8dbc + + + 55e7d3ff-859f-40c9-af2f-069d6b54dd1c + 773393aa-361d-4ef6-8592-439c4e0a43c6 + + + + ТестовыйОтчет + + + ru + Тестовый отчет + + + + + + + + + + + + + + + diff --git "a/tests/unit/utils/\320\232\320\273\320\260\321\201\321\201\321\213/\320\224\320\260\320\275\320\275\321\213\320\265\320\236\320\261\321\200\320\260\320\261\320\276\321\202\320\276\320\272.os" "b/tests/unit/utils/\320\232\320\273\320\260\321\201\321\201\321\213/\320\224\320\260\320\275\320\275\321\213\320\265\320\236\320\261\321\200\320\260\320\261\320\276\321\202\320\276\320\272.os" index e419f5fd..aac0ad5e 100644 --- "a/tests/unit/utils/\320\232\320\273\320\260\321\201\321\201\321\213/\320\224\320\260\320\275\320\275\321\213\320\265\320\236\320\261\321\200\320\260\320\261\320\276\321\202\320\276\320\272.os" +++ "b/tests/unit/utils/\320\232\320\273\320\260\321\201\321\201\321\213/\320\224\320\260\320\275\320\275\321\213\320\265\320\236\320\261\321\200\320\260\320\261\320\276\321\202\320\276\320\272.os" @@ -1,7 +1,7 @@ // BSLLS:NumberOfValuesInStructureConstructor-off // BSLLS:MissingParameterDescription-off // BSLLS:MissingReturnedValueDescription-off -// Тестовые данные: внешние обработки 1С (XML-исходники, EPF-файлы). +// Тестовые данные: внешние обработки и отчёты 1С (XML-исходники, EPF/ERF-файлы). // Используются в тестах СервисОбработок. #Использовать tempfiles @@ -14,13 +14,47 @@ Каталог = ВременныеФайлы.СоздатьКаталог(); ПутьXml = ОбъединитьПути(Каталог, ИмяОбработки + ".xml"); - ЗаписатьСодержимоеXml(ПутьXml, ИмяОбработки); + ЗаписатьСодержимоеXml(ПутьXml, ИмяОбработки, "ExternalDataProcessor"); Возврат Новый Структура("Каталог, ФайлXml, ИмяОбработки", Каталог, ПутьXml, ИмяОбработки); КонецФункции +// Создать временный каталог с одним XML-файлом внешнего отчёта. +// Возвращает Структура: Каталог, ФайлXml, ИмяОтчета. +Функция КаталогСОтчетом(Знач ИмяОтчета = "ТестовыйОтчет") Экспорт + + Каталог = ВременныеФайлы.СоздатьКаталог(); + ПутьXml = ОбъединитьПути(Каталог, ИмяОтчета + ".xml"); + ЗаписатьСодержимоеXml(ПутьXml, ИмяОтчета, "ExternalReport"); + + Возврат Новый Структура("Каталог, ФайлXml, ИмяОтчета", + Каталог, ПутьXml, ИмяОтчета); + +КонецФункции + +// Создать временный каталог с двумя подкаталогами: обработка и внешний отчёт. +// Возвращает Структура: Каталог, ФайлОбработки, ИмяОбработки, ФайлОтчета, ИмяОтчета. +Функция КаталогСОбработкойИОтчетом(Знач ИмяОбработки = "МояОбработка", Знач ИмяОтчета = "МойОтчет") Экспорт + + Корень = ВременныеФайлы.СоздатьКаталог(); + + КаталогОбработки = ОбъединитьПути(Корень, ИмяОбработки); + СоздатьКаталог(КаталогОбработки); + ПутьОбработки = ОбъединитьПути(КаталогОбработки, ИмяОбработки + ".xml"); + ЗаписатьСодержимоеXml(ПутьОбработки, ИмяОбработки, "ExternalDataProcessor"); + + КаталогОтчета = ОбъединитьПути(Корень, ИмяОтчета); + СоздатьКаталог(КаталогОтчета); + ПутьОтчета = ОбъединитьПути(КаталогОтчета, ИмяОтчета + ".xml"); + ЗаписатьСодержимоеXml(ПутьОтчета, ИмяОтчета, "ExternalReport"); + + Возврат Новый Структура("Каталог, ФайлОбработки, ИмяОбработки, ФайлОтчета, ИмяОтчета", + Корень, ПутьОбработки, ИмяОбработки, ПутьОтчета, ИмяОтчета); + +КонецФункции + // Создать пустой временный каталог (без XML). Функция ПустойКаталог() Экспорт Возврат ВременныеФайлы.СоздатьКаталог(); @@ -38,7 +72,7 @@ Подкаталог = ОбъединитьПути(Корень, ИмяОбработки); СоздатьКаталог(Подкаталог); ПутьXml = ОбъединитьПути(Подкаталог, ИмяОбработки + ".xml"); - ЗаписатьСодержимоеXml(ПутьXml, ИмяОбработки); + ЗаписатьСодержимоеXml(ПутьXml, ИмяОбработки, "ExternalDataProcessor"); ПодКаталоги.Добавить(Подкаталог); КонецЦикла; @@ -49,16 +83,13 @@ // Создать временный EPF-файл (плейсхолдер, реальная EPF-структура не нужна для unit-тестов). // Возвращает Структура: ПутьКФайлу, Каталог, ИмяБезРасширения. Функция ВременныйEpf(Знач Имя = "ТестоваяОбработка") Экспорт + Возврат ВременныйФайлВнешнегоОбъекта(Имя, "epf"); +КонецФункции - Каталог = ВременныеФайлы.СоздатьКаталог(); - Путь = ОбъединитьПути(Каталог, Имя + ".epf"); - ТД = Новый ТекстовыйДокумент; - ТД.УстановитьТекст("epf-placeholder"); - ТД.Записать(Путь); - - Возврат Новый Структура("ПутьКФайлу, Каталог, ИмяБезРасширения", - Путь, Каталог, Имя); - +// Создать временный ERF-файл внешнего отчёта (плейсхолдер). +// Возвращает Структура: ПутьКФайлу, Каталог, ИмяБезРасширения. +Функция ВременныйErf(Знач Имя = "ТестовыйОтчет") Экспорт + Возврат ВременныйФайлВнешнегоОбъекта(Имя, "erf"); КонецФункции // Создать временный каталог с N EPF-файлами. @@ -67,31 +98,59 @@ Корень = ВременныеФайлы.СоздатьКаталог(); Файлы = Новый Массив; Для Сч = 1 По Количество Цикл - Имя = "Обработка" + Сч + ".epf"; - Путь = ОбъединитьПути(Корень, Имя); - ТД = Новый ТекстовыйДокумент; - ТД.УстановитьТекст("epf-placeholder"); - ТД.Записать(Путь); - Файлы.Добавить(Путь); + Файлы.Добавить(ЗаписатьФайлЗаглушку(Корень, "Обработка" + Сч, "epf")); КонецЦикла; Возврат Новый Структура("Каталог, Файлы", Корень, Файлы); КонецФункции +// Создать временный каталог с одним EPF-файлом обработки и одним ERF-файлом отчёта. +// Возвращает Структура: Каталог, ФайлОбработки, ИмяОбработки, ФайлОтчета, ИмяОтчета. +Функция КаталогСФайламиОбработкиИОтчета(Знач ИмяОбработки = "МояОбработка", Знач ИмяОтчета = "МойОтчет") Экспорт + + Корень = ВременныеФайлы.СоздатьКаталог(); + + Возврат Новый Структура("Каталог, ФайлОбработки, ИмяОбработки, ФайлОтчета, ИмяОтчета", + Корень, + ЗаписатьФайлЗаглушку(Корень, ИмяОбработки, "epf"), ИмяОбработки, + ЗаписатьФайлЗаглушку(Корень, ИмяОтчета, "erf"), ИмяОтчета); + +КонецФункции + #КонецОбласти #Область СлужебныеПроцедурыИФункции -Процедура ЗаписатьСодержимоеXml(Знач Путь, Знач ИмяОбработки) +Функция ВременныйФайлВнешнегоОбъекта(Знач Имя, Знач Расширение) + + Каталог = ВременныеФайлы.СоздатьКаталог(); + + Возврат Новый Структура("ПутьКФайлу, Каталог, ИмяБезРасширения", + ЗаписатьФайлЗаглушку(Каталог, Имя, Расширение), Каталог, Имя); + +КонецФункции + +Функция ЗаписатьФайлЗаглушку(Знач Каталог, Знач Имя, Знач Расширение) + + Путь = ОбъединитьПути(Каталог, Имя + "." + Расширение); + ТД = Новый ТекстовыйДокумент; + ТД.УстановитьТекст(Расширение + "-placeholder"); + ТД.Записать(Путь); + + Возврат Путь; + +КонецФункции + +Процедура ЗаписатьСодержимоеXml(Знач Путь, Знач ИмяОбъекта, Знач ТегОбъекта) Содержимое = СтрШаблон( "" + "" - + "" + + "<%2 uuid=""00000000-0000-0000-0000-000000000001"">" + "%1" - + "" + + "" + "", - ИмяОбработки); + ИмяОбъекта, ТегОбъекта); ТД = Новый ТекстовыйДокумент; ТД.УстановитьТекст(Содержимое); ТД.Записать(Путь, КодировкаТекста.UTF8); diff --git "a/tests/unit/\320\224\320\262\320\270\320\266\320\272\320\270/\320\242\320\265\321\201\321\202\320\224\320\262\320\270\320\266\320\276\320\272Ibcmd.os" "b/tests/unit/\320\224\320\262\320\270\320\266\320\272\320\270/\320\242\320\265\321\201\321\202\320\224\320\262\320\270\320\266\320\276\320\272Ibcmd.os" index 1ac7538a..178b6684 100644 --- "a/tests/unit/\320\224\320\262\320\270\320\266\320\272\320\270/\320\242\320\265\321\201\321\202\320\224\320\262\320\270\320\266\320\276\320\272Ibcmd.os" +++ "b/tests/unit/\320\224\320\262\320\270\320\266\320\272\320\270/\320\242\320\265\321\201\321\202\320\224\320\262\320\270\320\266\320\276\320\272Ibcmd.os" @@ -49,6 +49,13 @@ Возврат К; КонецФункции +// Абсолютный путь для ожиданий: движок нормализует пути перед передачей в ibcmd, +// а литерал вида "C:\my.cf" абсолютным считается только на Windows - на Linux он +// относительный и после нормализации превращается в <текущий каталог>/C:\my.cf. +Функция АбсолютныйПуть(Знач Имя) + Возврат Новый Файл(Имя).ПолноеИмя; +КонецФункции + #Область ПлатформаИФабрика &Тест @@ -95,7 +102,7 @@ &Тест Процедура ТестДолжен_УстановитьКонтекстСервернойИБ_ЕслиЗаданТипСУБД() Экспорт - Движок.ЗагрузитьКонфигурациюИзФайла(ПарПодключенияСервер, "C:\\my.cf"); + Движок.ЗагрузитьКонфигурациюИзФайла(ПарПодключенияСервер, "C:\my.cf"); Вызов_ = Вызов("УстановитьПараметрыСервернойИБ"); Ожидаем.Что(Вызов_).Заполнено(); Ожидаем.Что(Вызов_.Параметры.Тип).Равно("PostgreSQL"); @@ -105,7 +112,7 @@ &Тест Процедура ТестДолжен_УстановитьКонтекстФайловойИБ_ИзКаталогБазы() Экспорт - Движок.ЗагрузитьКонфигурациюИзФайла(ПарПодключенияФайл, "C:\\my.cf"); + Движок.ЗагрузитьКонфигурациюИзФайла(ПарПодключенияФайл, "C:\my.cf"); Вызов_ = Вызов("УстановитьПараметрыФайловойИБ"); Ожидаем.Что(Вызов_).Заполнено(); Ожидаем.Что(Вызов_.Параметры).Равно("C:\\base"); @@ -115,7 +122,7 @@ Процедура ТестДолжен_ПропуститьАвторизацию_ЕслиПользовательНеЗадан() Экспорт ПП = Новый Структура("СтрокаПодключения, Пользователь, Пароль, КаталогБазы", "File=b", "", "", "C:\\b"); - Движок.ЗагрузитьКонфигурациюИзФайла(ПП, "C:\\my.cf"); + Движок.ЗагрузитьКонфигурациюИзФайла(ПП, "C:\my.cf"); Ожидаем.Что(КоличествоВызовов("УстановитьПараметрыАвторизацииИБ")).Равно(0); КонецПроцедуры @@ -125,11 +132,34 @@ &Тест Процедура ТестДолжен_ЗагрузитьКонфигурациюИзФайлов_БезСписка() Экспорт - Движок.ЗагрузитьКонфигурациюИзФайлов(ПарПодключенияФайл, "C:\\src"); - Ожидаем.Что(Вызов("ЗагрузитьКонфигурациюИзФайлов").Параметры.Каталог).Равно("C:\\src"); + ПутьИсходников = АбсолютныйПуть("src"); + Движок.ЗагрузитьКонфигурациюИзФайлов(ПарПодключенияФайл, ПутьИсходников); + Ожидаем.Что(Вызов("ЗагрузитьКонфигурациюИзФайлов").Параметры.Каталог).Равно(ПутьИсходников); Ожидаем.Что(КоличествоВызовов("ЗагрузитьВыбранныеФайлыКонфигурации")).Равно(0); КонецПроцедуры +// ibcmd падает на относительном каталоге исходников с префиксом "./" - +// "файл <путь> отсутствует либо поврежден" на случайных файлах. Передаём абсолютный путь. +&Тест +Процедура ТестДолжен_ПередатьАбсолютныйКаталогИсходников_ЕслиПутьОтносительный() Экспорт + Движок.ЗагрузитьКонфигурациюИзФайлов(ПарПодключенияФайл, "./build/src/cf"); + Ожидаем.Что(Вызов("ЗагрузитьКонфигурациюИзФайлов").Параметры.Каталог) + .Равно(АбсолютныйПуть("./build/src/cf")); +КонецПроцедуры + +&Тест +Процедура ТестДолжен_ПередатьАбсолютныйБазовыйКаталог_ПриВыборочнойЗагрузке() Экспорт + КатТмп = ВременныеФайлы.СоздатьКаталог(); + ПутьСписка = ОбъединитьПути(КатТмп, "list.txt"); + Запись = Новый ЗаписьТекста(ПутьСписка, "UTF-8"); + Запись.ЗаписатьСтроку("Configuration.xml"); + Запись.Закрыть(); + + Движок.ЗагрузитьКонфигурациюИзФайлов(ПарПодключенияФайл, "./build/src/cf", Неопределено, ПутьСписка); + Ожидаем.Что(Вызов("ЗагрузитьВыбранныеФайлыКонфигурации").Параметры.Каталог) + .Равно(АбсолютныйПуть("./build/src/cf")); +КонецПроцедуры + &Тест Процедура ТестДолжен_ЗагрузитьВыбранныеФайлы_ЕслиЗаданСписок() Экспорт КатТмп = ВременныеФайлы.СоздатьКаталог(); @@ -139,7 +169,7 @@ Запись.ЗаписатьСтроку("Catalogs/Товары.xml"); Запись.Закрыть(); - Движок.ЗагрузитьКонфигурациюИзФайлов(ПарПодключенияФайл, "C:\\src", Неопределено, ПутьСписка); + Движок.ЗагрузитьКонфигурациюИзФайлов(ПарПодключенияФайл, "C:\src", Неопределено, ПутьСписка); Вызов_ = Вызов("ЗагрузитьВыбранныеФайлыКонфигурации"); Ожидаем.Что(Вызов_).Заполнено(); Ожидаем.Что(Вызов_.Параметры.Файлы.Количество()).Равно(2); @@ -153,21 +183,30 @@ Запись.ЗаписатьСтроку(""); Запись.Закрыть(); - Движок.ЗагрузитьКонфигурациюИзФайлов(ПарПодключенияФайл, "C:\\src", Неопределено, ПутьСписка); + Движок.ЗагрузитьКонфигурациюИзФайлов(ПарПодключенияФайл, "C:\src", Неопределено, ПутьСписка); Ожидаем.Что(КоличествоВызовов("ЗагрузитьВыбранныеФайлыКонфигурации")).Равно(0); Ожидаем.Что(КоличествоВызовов("ЗагрузитьКонфигурациюИзФайлов")).Равно(1); КонецПроцедуры &Тест Процедура ТестДолжен_ЗагрузитьКонфигурациюИзФайла() Экспорт - Движок.ЗагрузитьКонфигурациюИзФайла(ПарПодключенияФайл, "C:\\my.cf"); - Ожидаем.Что(Вызов("ЗагрузитьКонфигурацию").Параметры.Путь).Равно("C:\\my.cf"); + ПутьCf = АбсолютныйПуть("my.cf"); + Движок.ЗагрузитьКонфигурациюИзФайла(ПарПодключенияФайл, ПутьCf); + Ожидаем.Что(Вызов("ЗагрузитьКонфигурацию").Параметры.Путь).Равно(ПутьCf); +КонецПроцедуры + +&Тест +Процедура ТестДолжен_ПередатьАбсолютныйПутьКФайлуCf_ЕслиПутьОтносительный() Экспорт + Движок.ЗагрузитьКонфигурациюИзФайла(ПарПодключенияФайл, "./build/1cv8.cf"); + Ожидаем.Что(Вызов("ЗагрузитьКонфигурацию").Параметры.Путь) + .Равно(АбсолютныйПуть("./build/1cv8.cf")); КонецПроцедуры &Тест Процедура ТестДолжен_ВыгрузитьКонфигурациюВФайл() Экспорт - Движок.ВыгрузитьКонфигурациюВФайл(ПарПодключенияФайл, "C:\\out.cf"); - Ожидаем.Что(Вызов("ВыгрузитьКонфигурациюВФайл").Параметры.Путь).Равно("C:\\out.cf"); + ПутьCf = АбсолютныйПуть("out.cf"); + Движок.ВыгрузитьКонфигурациюВФайл(ПарПодключенияФайл, ПутьCf); + Ожидаем.Что(Вызов("ВыгрузитьКонфигурациюВФайл").Параметры.Путь).Равно(ПутьCf); КонецПроцедуры &Тест @@ -194,14 +233,16 @@ &Тест Процедура ТестДолжен_ЗагрузитьИнфобазуИзDT() Экспорт - Движок.ЗагрузитьИнфобазуИзФайла(ПарПодключенияФайл, "C:\\dump.dt"); - Ожидаем.Что(Вызов("ЗагрузитьДанныеИБ").Параметры).Равно("C:\\dump.dt"); + ПутьDT = АбсолютныйПуть("dump.dt"); + Движок.ЗагрузитьИнфобазуИзФайла(ПарПодключенияФайл, ПутьDT); + Ожидаем.Что(Вызов("ЗагрузитьДанныеИБ").Параметры).Равно(ПутьDT); КонецПроцедуры &Тест Процедура ТестДолжен_ВыгрузитьИнфобазуВDT() Экспорт - Движок.ВыгрузитьИнфобазуВФайл(ПарПодключенияФайл, "C:\\out.dt"); - Ожидаем.Что(Вызов("ВыгрузитьДанныеИБ").Параметры).Равно("C:\\out.dt"); + ПутьDT = АбсолютныйПуть("out.dt"); + Движок.ВыгрузитьИнфобазуВФайл(ПарПодключенияФайл, ПутьDT); + Ожидаем.Что(Вызов("ВыгрузитьДанныеИБ").Параметры).Равно(ПутьDT); КонецПроцедуры #КонецОбласти @@ -249,22 +290,23 @@ &Тест Процедура ТестДолжен_ЗагрузитьРасширениеИзФайла() Экспорт - Движок.ЗагрузитьРасширениеИзФайла(ПарПодключенияФайл, "C:\\ext.cfe", "MyExt"); + ПутьCfe = АбсолютныйПуть("ext.cfe"); + Движок.ЗагрузитьРасширениеИзФайла(ПарПодключенияФайл, ПутьCfe, "MyExt"); Вызов_ = Вызов("ЗагрузитьКонфигурацию"); - Ожидаем.Что(Вызов_.Параметры.Путь).Равно("C:\\ext.cfe"); + Ожидаем.Что(Вызов_.Параметры.Путь).Равно(ПутьCfe); Ожидаем.Что(Вызов_.Параметры.Имя).Равно("MyExt"); КонецПроцедуры &Тест Процедура ТестДолжен_ВыгрузитьРасширениеВФайл() Экспорт - Движок.ВыгрузитьРасширениеВФайл(ПарПодключенияФайл, "C:\\ext.cfe", "MyExt"); + Движок.ВыгрузитьРасширениеВФайл(ПарПодключенияФайл, "C:\ext.cfe", "MyExt"); Вызов_ = Вызов("ВыгрузитьКонфигурациюВФайл"); Ожидаем.Что(Вызов_.Параметры.Имя).Равно("MyExt"); КонецПроцедуры &Тест Процедура ТестДолжен_ЗагрузитьРасширениеИзФайлов_БезСписка() Экспорт - Движок.ЗагрузитьРасширениеИзФайлов(ПарПодключенияФайл, "C:\\src", "MyExt"); + Движок.ЗагрузитьРасширениеИзФайлов(ПарПодключенияФайл, "C:\src", "MyExt"); Вызов_ = Вызов("ЗагрузитьКонфигурациюИзФайлов"); Ожидаем.Что(Вызов_.Параметры.Имя).Равно("MyExt"); КонецПроцедуры @@ -277,7 +319,7 @@ Запись.ЗаписатьСтроку("Ext.xml"); Запись.Закрыть(); - Движок.ЗагрузитьРасширениеИзФайлов(ПарПодключенияФайл, "C:\\src", "MyExt", Неопределено, ПутьСписка); + Движок.ЗагрузитьРасширениеИзФайлов(ПарПодключенияФайл, "C:\src", "MyExt", Неопределено, ПутьСписка); Вызов_ = Вызов("ЗагрузитьВыбранныеФайлыКонфигурации"); Ожидаем.Что(Вызов_).Заполнено(); Ожидаем.Что(Вызов_.Параметры.Имя).Равно("MyExt"); @@ -314,7 +356,7 @@ &Тест Процедура ТестДолжен_ВернутьПусто_ЕслиКешНеЗадан() Экспорт - Результат = Движок.ПолучитьИзмененияКонфигурации(ПарПодключенияФайл, "C:\\src"); + Результат = Движок.ПолучитьИзмененияКонфигурации(ПарПодключенияФайл, "C:\src"); Ожидаем.Что(Результат.ТребуетсяПолнаяЗагрузка).ЭтоЛожь(); Ожидаем.Что(Результат.ИзмененныеФайлы.Количество()).Равно(0); КонецПроцедуры @@ -322,7 +364,7 @@ &Тест Процедура ТестДолжен_ВернутьПусто_ЕслиФайлКешаНеСуществует() Экспорт Результат = Движок.ПолучитьИзмененияКонфигурации( - ПарПодключенияФайл, "C:\\src", "C:\\not-exists\\dump-info.xml"); + ПарПодключенияФайл, "C:\src", "C:\\not-exists\\dump-info.xml"); Ожидаем.Что(Результат.ИзмененныеФайлы.Количество()).Равно(0); КонецПроцедуры @@ -335,7 +377,7 @@ Запись.Закрыть(); Менеджер.СБросанием("ВыгрузитьВФайлИзмененияКонфигурации"); - Результат = Движок.ПолучитьИзмененияКонфигурации(ПарПодключенияФайл, "C:\\src", ПутьКеша); + Результат = Движок.ПолучитьИзмененияКонфигурации(ПарПодключенияФайл, "C:\src", ПутьКеша); Ожидаем.Что(Результат.ТребуетсяПолнаяЗагрузка).ЭтоЛожь(); Ожидаем.Что(Результат.ИзмененныеФайлы.Количество()).Равно(0); diff --git "a/tests/unit/\320\241\320\265\321\200\320\262\320\270\321\201\321\213/\320\242\320\265\321\201\321\202\320\241\320\265\321\200\320\262\320\270\321\201\320\236\320\261\321\200\320\260\320\261\320\276\321\202\320\276\320\272.os" "b/tests/unit/\320\241\320\265\321\200\320\262\320\270\321\201\321\213/\320\242\320\265\321\201\321\202\320\241\320\265\321\200\320\262\320\270\321\201\320\236\320\261\321\200\320\260\320\261\320\276\321\202\320\276\320\272.os" index 0b9ba7ab..c2e79a9d 100644 --- "a/tests/unit/\320\241\320\265\321\200\320\262\320\270\321\201\321\213/\320\242\320\265\321\201\321\202\320\241\320\265\321\200\320\262\320\270\321\201\320\236\320\261\321\200\320\260\320\261\320\276\321\202\320\276\320\272.os" +++ "b/tests/unit/\320\241\320\265\321\200\320\262\320\270\321\201\321\213/\320\242\320\265\321\201\321\202\320\241\320\265\321\200\320\262\320\270\321\201\320\236\320\261\321\200\320\260\320\261\320\276\321\202\320\276\320\272.os" @@ -1,8 +1,9 @@ // BSLLS-off // Юнит-тесты СервисОбработок. // Реальные движки (v8runner, ibcmd) не вызываются - все взаимодействия замоканы. -// Покрытие: оркестрация сборки/разборки EPF, поиск XML, выбор каталога выгрузки, -// очистка временной базы при ошибках, рекурсивный обход. +// Покрытие: оркестрация сборки/разборки EPF и ERF, поиск XML, выбор каталога выгрузки +// и расширения результата по типу объекта (ExternalDataProcessor → .epf, +// ExternalReport → .erf), очистка временной базы при ошибках, рекурсивный обход. #Использовать asserts #Использовать moskito @@ -69,6 +70,29 @@ КонецПроцедуры +&Тест +Процедура ТестДолжен_СобратьВнешнийОтчет_ВФайлErf() Экспорт + + // Дано - каталог с XML внешнего отчёта (ExternalReport), а не обработки + КаталогДанные = Обработки.КаталогСОтчетом("МойОтчет"); + КаталогВыгрузки = ВременныеФайлы.СоздатьКаталог(); + ОжидаемыйПуть = ОбъединитьПути(КаталогВыгрузки, "МойОтчет.erf"); + + МокДвижок = Мок.Получить(Новый ДвижокКонфигуратор); + МокДвижок.Когда().СоздатьВременнуюБазу(Любое) + .ТогдаВозвращает(Подключения.Файловая(ВременныеФайлы.СоздатьКаталог())); + + Сервис = Новый БилдерСервисаОбработок().СОдинаковымДвижком(МокДвижок).Собрать(); + + // Когда + Сервис.СобратьОбработку(КаталогДанные.Каталог, КаталогВыгрузки); + + // Тогда - отчёт собран в .erf, а не в .epf + МокДвижок.ПроверитьЧтоВызывалсяМетод().СобратьВнешнююОбработкуИзФайлов( + Любое, КаталогДанные.ФайлXml, ОжидаемыйПуть, Любое); + +КонецПроцедуры + &Тест Процедура ТестДолжен_ВыброситьИсключение_ЕслиВКаталогеНетXml() Экспорт @@ -137,6 +161,29 @@ КонецПроцедуры +&Тест +Процедура ТестДолжен_СобратьОбработкуИОтчет_СРазнымиРасширениями() Экспорт + + // Дано - в дереве лежат и обработка, и внешний отчёт + КаталогДанные = Обработки.КаталогСОбработкойИОтчетом("МояОбработка", "МойОтчет"); + КаталогВыгрузки = ВременныеФайлы.СоздатьКаталог(); + МокДвижок = Мок.Получить(Новый ДвижокКонфигуратор); + МокДвижок.Когда().СоздатьВременнуюБазу(Любое) + .ТогдаВозвращает(Подключения.Файловая(ВременныеФайлы.СоздатьКаталог())); + + Сервис = Новый БилдерСервисаОбработок().СОдинаковымДвижком(МокДвижок).Собрать(); + + // Когда + Сервис.СобратьОбработкиРекурсивно(КаталогДанные.Каталог, КаталогВыгрузки); + + // Тогда - каждый объект собран со своим расширением + МокДвижок.ПроверитьЧтоВызывалсяМетод().СобратьВнешнююОбработкуИзФайлов( + Любое, КаталогДанные.ФайлОбработки, ОбъединитьПути(КаталогВыгрузки, "МояОбработка.epf"), Любое); + МокДвижок.ПроверитьЧтоВызывалсяМетод().СобратьВнешнююОбработкуИзФайлов( + Любое, КаталогДанные.ФайлОтчета, ОбъединитьПути(КаталогВыгрузки, "МойОтчет.erf"), Любое); + +КонецПроцедуры + &Тест Процедура ТестДолжен_ВыброситьИсключение_ЕслиРекурсивноНичегоНеНайдено() Экспорт @@ -227,6 +274,29 @@ КонецПроцедуры +&Тест +Процедура ТестДолжен_РазобратьErfВнешнегоОтчета() Экспорт + + // Дано + ErfДанные = Обработки.ВременныйErf("МойОтчет"); + КаталогВыгрузки = ВременныеФайлы.СоздатьКаталог(); + ОжидаемыйКаталог = ОбъединитьПути(КаталогВыгрузки, "МойОтчет"); + + МокДвижок = Мок.Получить(Новый ДвижокКонфигуратор); + МокДвижок.Когда().СоздатьВременнуюБазу(Любое) + .ТогдаВозвращает(Подключения.Файловая(ВременныеФайлы.СоздатьКаталог())); + + Сервис = Новый БилдерСервисаОбработок().СОдинаковымДвижком(МокДвижок).Собрать(); + + // Когда + Сервис.РазобратьОбработку(ErfДанные.ПутьКФайлу, КаталогВыгрузки); + + // Тогда + МокДвижок.ПроверитьЧтоВызывалсяМетод().РазобратьВнешнююОбработкуВФайлы( + Любое, ErfДанные.ПутьКФайлу, ОжидаемыйКаталог, Любое); + +КонецПроцедуры + &Тест Процедура ТестДолжен_ВыброситьИсключение_ЕслиEpfНеСуществует() Экспорт @@ -294,6 +364,29 @@ КонецПроцедуры +&Тест +Процедура ТестДолжен_РазобратьИEpfИErfИзКаталога() Экспорт + + // Дано - в каталоге и обработка, и внешний отчёт + Данные = Обработки.КаталогСФайламиОбработкиИОтчета("МояОбработка", "МойОтчет"); + КаталогВыгрузки = ВременныеФайлы.СоздатьКаталог(); + МокДвижок = Мок.Получить(Новый ДвижокКонфигуратор); + МокДвижок.Когда().СоздатьВременнуюБазу(Любое) + .ТогдаВозвращает(Подключения.Файловая(ВременныеФайлы.СоздатьКаталог())); + + Сервис = Новый БилдерСервисаОбработок().СОдинаковымДвижком(МокДвижок).Собрать(); + + // Когда + Сервис.РазобратьОбработкиИзКаталога(Данные.Каталог, Ложь, КаталогВыгрузки); + + // Тогда - разобраны оба файла, каждый в каталог по своему имени + МокДвижок.ПроверитьЧтоВызывалсяМетод().РазобратьВнешнююОбработкуВФайлы( + Любое, Данные.ФайлОбработки, ОбъединитьПути(КаталогВыгрузки, "МояОбработка"), Любое); + МокДвижок.ПроверитьЧтоВызывалсяМетод().РазобратьВнешнююОбработкуВФайлы( + Любое, Данные.ФайлОтчета, ОбъединитьПути(КаталогВыгрузки, "МойОтчет"), Любое); + +КонецПроцедуры + &Тест Процедура ТестДолжен_ВыброситьИсключение_ЕслиВКаталогеНетEpf() Экспорт @@ -427,6 +520,69 @@ КонецПроцедуры +&Тест +Процедура ТестДолжен_СобратьОтчетИзEDTПроекта_ВФайлErf() Экспорт + + // Дано - раскладка export 1С:EDT: ExternalDataProcessors/ и ExternalReports/ + КаталогXml = ВременныеФайлы.СоздатьКаталог(); + ПутьОбработки = ПутьВыгрузкиEDT(КаталогXml, "ExternalDataProcessors", "МояОбработка"); + ПутьОтчета = ПутьВыгрузкиEDT(КаталогXml, "ExternalReports", "МойОтчет"); + ЗаписатьТекстВФайл(ПутьОбработки, ""); + ЗаписатьТекстВФайл(ПутьОтчета, ""); + ФайлыВыгрузки = Новый Массив; + ФайлыВыгрузки.Добавить(Новый Файл(ПутьОбработки)); + ФайлыВыгрузки.Добавить(Новый Файл(ПутьОтчета)); + + МокEDT = Мок.Получить(Новый СервисEDT); + МокEDT.Когда().ЭтоПроектВнешнихОбъектовEDT(Любое, Любое).ТогдаВозвращает(Истина); + МокEDT.Когда().ЭкспортироватьВнешниеОбъекты(Любое, Любое, Любое).ТогдаВозвращает(ФайлыВыгрузки); + МокДвижок = Мок.Получить(Новый ДвижокКонфигуратор); + МокДвижок.Когда().СоздатьВременнуюБазу(Любое) + .ТогдаВозвращает(Подключения.Файловая(ВременныеФайлы.СоздатьКаталог())); + КаталогOut = ВременныеФайлы.СоздатьКаталог(); + Сервис = Новый БилдерСервисаОбработок().СОдинаковымДвижком(МокДвижок).СEDT(МокEDT).Собрать(); + + // Когда + Сервис.СобратьОбработку("C:\edt-project", КаталогOut, Ложь, Неопределено, Неопределено, + Новый Структура("Формат, Версия, Workspace", "edt", "", "")); + + // Тогда - обработка собрана в .epf, отчёт - в .erf + МокДвижок.ПроверитьЧтоВызывалсяМетод().СобратьВнешнююОбработкуИзФайлов( + Любое, ПутьОбработки, ОбъединитьПути(КаталогOut, "МояОбработка.epf"), Любое); + МокДвижок.ПроверитьЧтоВызывалсяМетод().СобратьВнешнююОбработкуИзФайлов( + Любое, ПутьОтчета, ОбъединитьПути(КаталогOut, "МойОтчет.erf"), Любое); + +КонецПроцедуры + +&Тест +Процедура ТестДолжен_ОпределитьТипОбъектаEDT_ПоКаталогуРаскладки() Экспорт + + // Дано - корневой тег не распознан, тип берётся из каталога раскладки export + КаталогXml = ВременныеФайлы.СоздатьКаталог(); + ПутьОтчета = ПутьВыгрузкиEDT(КаталогXml, "ExternalReports", "МойОтчет"); + ЗаписатьТекстВФайл(ПутьОтчета, ""); + ФайлыВыгрузки = Новый Массив; + ФайлыВыгрузки.Добавить(Новый Файл(ПутьОтчета)); + + МокEDT = Мок.Получить(Новый СервисEDT); + МокEDT.Когда().ЭтоПроектВнешнихОбъектовEDT(Любое, Любое).ТогдаВозвращает(Истина); + МокEDT.Когда().ЭкспортироватьВнешниеОбъекты(Любое, Любое, Любое).ТогдаВозвращает(ФайлыВыгрузки); + МокДвижок = Мок.Получить(Новый ДвижокКонфигуратор); + МокДвижок.Когда().СоздатьВременнуюБазу(Любое) + .ТогдаВозвращает(Подключения.Файловая(ВременныеФайлы.СоздатьКаталог())); + КаталогOut = ВременныеФайлы.СоздатьКаталог(); + Сервис = Новый БилдерСервисаОбработок().СОдинаковымДвижком(МокДвижок).СEDT(МокEDT).Собрать(); + + // Когда + Сервис.СобратьОбработку("C:\edt-project", КаталогOut, Ложь, Неопределено, Неопределено, + Новый Структура("Формат, Версия, Workspace", "edt", "", "")); + + // Тогда - объект из ExternalReports/ собран в .erf + МокДвижок.ПроверитьЧтоВызывалсяМетод().СобратьВнешнююОбработкуИзФайлов( + Любое, ПутьОтчета, ОбъединитьПути(КаталогOut, "МойОтчет.erf"), Любое); + +КонецПроцедуры + &Тест Процедура ТестДолжен_СобиратьИзXMLНапрямую_ЕслиИсточникНеEDT() Экспорт @@ -454,4 +610,11 @@ Запись.Закрыть(); КонецПроцедуры +// Путь корневого XML в раскладке export 1С:EDT: <КаталогВыгрузки>/<ТипОбъекта>/<Имя>.xml +Функция ПутьВыгрузкиEDT(Знач КаталогВыгрузки, Знач ТипОбъекта, Знач Имя) + КаталогТипа = ОбъединитьПути(КаталогВыгрузки, ТипОбъекта); + СоздатьКаталог(КаталогТипа); + Возврат ОбъединитьПути(КаталогТипа, Имя + ".xml"); +КонецФункции + #КонецОбласти