diff --git "a/src/cli/internal/isolated/\320\232\320\273\320\260\321\201\321\201\321\213/\320\236\320\277\320\270\321\201\320\260\320\275\320\270\320\265\320\232\320\276\320\275\321\201\320\276\320\273\321\214\320\275\320\276\320\263\320\276\320\237\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270\321\217.os" "b/src/cli/internal/isolated/\320\232\320\273\320\260\321\201\321\201\321\213/\320\236\320\277\320\270\321\201\320\260\320\275\320\270\320\265\320\232\320\276\320\275\321\201\320\276\320\273\321\214\320\275\320\276\320\263\320\276\320\237\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270\321\217.os" index a65b388..2449d87 100644 --- "a/src/cli/internal/isolated/\320\232\320\273\320\260\321\201\321\201\321\213/\320\236\320\277\320\270\321\201\320\260\320\275\320\270\320\265\320\232\320\276\320\275\321\201\320\276\320\273\321\214\320\275\320\276\320\263\320\276\320\237\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270\321\217.os" +++ "b/src/cli/internal/isolated/\320\232\320\273\320\260\321\201\321\201\321\213/\320\236\320\277\320\270\321\201\320\260\320\275\320\270\320\265\320\232\320\276\320\275\321\201\320\276\320\273\321\214\320\275\320\276\320\263\320\276\320\237\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270\321\217.os" @@ -12,5 +12,5 @@ КонецФункции Функция ВерсияПриложения() Экспорт - Возврат "0.4.1"; + Возврат "0.5.0"; КонецФункции diff --git "a/src/shared/\320\232\320\273\320\260\321\201\321\201\321\213/\320\227\320\260\320\277\321\203\321\201\320\272\320\260\321\202\320\265\320\273\321\214\320\242\320\265\321\201\321\202\320\270\321\200\320\276\320\262\320\260\320\275\320\270\321\217.os" "b/src/shared/\320\232\320\273\320\260\321\201\321\201\321\213/\320\227\320\260\320\277\321\203\321\201\320\272\320\260\321\202\320\265\320\273\321\214\320\242\320\265\321\201\321\202\320\270\321\200\320\276\320\262\320\260\320\275\320\270\321\217.os" index 3c2a2a4..9c39de7 100644 --- "a/src/shared/\320\232\320\273\320\260\321\201\321\201\321\213/\320\227\320\260\320\277\321\203\321\201\320\272\320\260\321\202\320\265\320\273\321\214\320\242\320\265\321\201\321\202\320\270\321\200\320\276\320\262\320\260\320\275\320\270\321\217.os" +++ "b/src/shared/\320\232\320\273\320\260\321\201\321\201\321\213/\320\227\320\260\320\277\321\203\321\201\320\272\320\260\321\202\320\265\320\273\321\214\320\242\320\265\321\201\321\202\320\270\321\200\320\276\320\262\320\260\320\275\320\270\321\217.os" @@ -28,6 +28,18 @@ // исполняется в прогоне с захватом экземпляра набора, поднятого // напрямую через Новый, пустая строка - совет по умолчанию // * РаскладкаЛога - Строка - Раскладка лога прогона, по умолчанию JSONРаскладкаСообщения +// * КаталогЯдра - Строка - Каталог ядра (core чужой поставки, рядом обязан лежать +// shared), которым выполняется прогон. Пустое значение - ядро, поставляемое +// с текущим экземпляром OneUnit. Нужен приложениям, которые поставляют +// OneUnit внутри себя, но прогоняют чужие тесты: тесты проекта тогда +// выполняются тем ядром, на которое проект рассчитан. +// Развязка при этом частичная. Точку входа строит по-прежнему построитель +// вызывающего приложения, а он завязан на состав ядра: имена желудей, +// имена деталек, настройки лога. Лишнюю детальку старое ядро пропустит, +// а вот ядру новее построителя нужной детальки никто не запишет. +// Дерево зависимостей прогона тоже остаётся прежним: lib.system +// и lib.additional собираются из окружения вызывающего процесса +// и oscript.cfg каталогов тестов // Функция ПараметрыЗапуска() Экспорт @@ -42,6 +54,7 @@ Параметры.Вставить("Импорты", Новый Массив); Параметры.Вставить("ЛямбдаСовета", ""); Параметры.Вставить("РаскладкаЛога", "JSONРаскладкаСообщения"); + Параметры.Вставить("КаталогЯдра", ""); Возврат Параметры; @@ -250,6 +263,13 @@ ФормироватьПокрытие = ЗначениеЗаполнено(Параметры.ПутьКОтчетуGenericCoverage) ИЛИ ЗначениеЗаполнено(Параметры.ПутьКОтчетуCobertura); + // Относительный каталог ядра разворачивается здесь, пока текущий каталог - каталог + // вызывающего. Дальше прогон переходит в РабочийКаталог, и тот же путь означал бы + // уже другой каталог - зависящий от того, где лежат чужие тесты + Если Параметры.Свойство("КаталогЯдра") И ЗначениеЗаполнено(Параметры.КаталогЯдра) Тогда + Параметры.КаталогЯдра = ФС.НормализоватьПуть(Параметры.КаталогЯдра); + КонецЕсли; + МенеджерВременныхФайлов = Новый МенеджерВременныхФайлов(); МенеджерВременныхФайлов.БазовыйКаталог = МенеджерВременныхФайлов.СоздатьКаталог(); diff --git "a/src/shared/\320\232\320\273\320\260\321\201\321\201\321\213/\320\237\320\276\321\201\321\202\321\200\320\276\320\270\321\202\320\265\320\273\321\214\320\242\320\276\321\207\320\272\320\270\320\222\321\205\320\276\320\264\320\260.os" "b/src/shared/\320\232\320\273\320\260\321\201\321\201\321\213/\320\237\320\276\321\201\321\202\321\200\320\276\320\270\321\202\320\265\320\273\321\214\320\242\320\276\321\207\320\272\320\270\320\222\321\205\320\276\320\264\320\260.os" index e36e3cc..d7a9f83 100644 --- "a/src/shared/\320\232\320\273\320\260\321\201\321\201\321\213/\320\237\320\276\321\201\321\202\321\200\320\276\320\270\321\202\320\265\320\273\321\214\320\242\320\276\321\207\320\272\320\270\320\222\321\205\320\276\320\264\320\260.os" +++ "b/src/shared/\320\232\320\273\320\260\321\201\321\201\321\213/\320\237\320\276\321\201\321\202\321\200\320\276\320\270\321\202\320\265\320\273\321\214\320\242\320\276\321\207\320\272\320\270\320\222\321\205\320\276\320\264\320\260.os" @@ -36,9 +36,9 @@ Лог.Отладка("Импорты считанные из тестов (Импорт=ПодключаетсяПоПути): %1", Импорты); - КаталогПриложения = ФС.НормализоватьПуть( - ОбъединитьПути(ОбъединитьПути(ТекущийСценарий().Каталог, "..", ".."), "core") - ); + КаталогПриложения = КаталогЯдра(ПараметрыЗапуска); + + Лог.Отладка("Ядро прогона: %1", КаталогПриложения); ПостроительСценария = Новый ПостроительДекоратора() .Импорт(Новый Импорт(КаталогПриложения).ТипПодключения(ТипыПодключенияБиблиотек.ПоПути)); @@ -356,8 +356,46 @@ ПараметрыЗапуска.Вставить("РаскладкаЛога", "JSONРаскладкаСообщения"); КонецЕсли; + Если Не ПараметрыЗапуска.Свойство("КаталогЯдра") Тогда + ПараметрыЗапуска.Вставить("КаталогЯдра", ""); + КонецЕсли; + КонецПроцедуры +// Возвращает каталог ядра, которым будет выполнен дочерний прогон. +// +// Параметры: +// ПараметрыЗапуска - Структура - Параметры запуска прогона, см. ЗапускательТестирования.ПараметрыЗапуска +// +// Возвращаемое значение: +// Строка - Каталог ядра. По умолчанию - ядро, лежащее рядом с этим классом +// +// Указанный каталог - это каталог core чужой поставки, и рядом с ним обязан лежать +// shared: ядро подключает его относительным путём, и на этом же держится наследование +// ядра изолированными прогонами. +// +Функция КаталогЯдра(ПараметрыЗапуска) + + Если ЗначениеЗаполнено(ПараметрыЗапуска.КаталогЯдра) Тогда + + Каталог = ФС.НормализоватьПуть(ПараметрыЗапуска.КаталогЯдра); + + // Иначе о промахе сказал бы дочерний процесс - и сказал бы про несуществующую + // библиотеку, а не про параметр, которым эту библиотеку выбрали + Если Не ФС.КаталогСуществует(Каталог) Тогда + ВызватьИсключение СтрШаблон("Каталог ядра прогона не найден: %1", Каталог); + КонецЕсли; + + Возврат Каталог; + + КонецЕсли; + + Возврат ФС.НормализоватьПуть( + ОбъединитьПути(ОбъединитьПути(ТекущийСценарий().Каталог, "..", ".."), "core") + ); + +КонецФункции + Функция КонфигурационныйФайл(Детальки, МенеджерВременныхФайлов, Лог) ПутиККонфигурационнымФайлам = Новый СписокМассив; diff --git "a/tests/\320\232\320\276\320\275\321\201\320\276\320\273\321\214\320\275\320\276\320\265\320\237\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270\320\265.os" "b/tests/\320\232\320\276\320\275\321\201\320\276\320\273\321\214\320\275\320\276\320\265\320\237\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270\320\265.os" index ea3eba7..b37a1be 100644 --- "a/tests/\320\232\320\276\320\275\321\201\320\276\320\273\321\214\320\275\320\276\320\265\320\237\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270\320\265.os" +++ "b/tests/\320\232\320\276\320\275\321\201\320\276\320\273\321\214\320\275\320\276\320\265\320\237\321\200\320\270\320\273\320\276\320\266\320\265\320\275\320\270\320\265.os" @@ -208,6 +208,140 @@ КонецПроцедуры +&Тест +Процедура ПрогонВыполняетсяЯдромРядомСПостроителем() Экспорт + + МенеджерВременныхФайлов = Новый МенеджерВременныхФайлов(); + МенеджерВременныхФайлов.БазовыйКаталог = МенеджерВременныхФайлов.СоздатьКаталог(); + + Построитель().СоздатьТочкуВхода( + Детальки(Массивы.ИзЭлементов("./tests/fixtures"), Новый Массив), + МенеджерВременныхФайлов, + Логирование.ПолучитьЛог("oscript.lib.oneunit.тесты"), + "// тестовая команда" + ); + + Ожидаем.Что(СтрНайти(СценарийПрогона(МенеджерВременныхФайлов), КаталогЯдраПоУмолчанию()), "Ядро по умолчанию") + .Больше(0); + + МенеджерВременныхФайлов.Удалить(); + +КонецПроцедуры + +&Тест +Процедура ЯдроПрогонаЗадаетсяПараметром() Экспорт + + // Приложению, которое поставляет OneUnit внутри себя, но прогоняет чужие тесты, + // нужно выполнять их ядром того проекта, а не своим + + МенеджерВременныхФайлов = Новый МенеджерВременныхФайлов(); + МенеджерВременныхФайлов.БазовыйКаталог = МенеджерВременныхФайлов.СоздатьКаталог(); + + // Каталог намеренно пустой и временный. Путь из проекта - те же tests/fixtures - + // попадает в сценарий импортами самих тестов, и утверждение проходило бы + // даже при полностью проигнорированном параметре + КаталогЯдра = ФС.НормализоватьПуть(МенеджерВременныхФайлов.СоздатьКаталог()); + + Параметры = Запускатель().ПараметрыЗапуска(); + Параметры.КаталогЯдра = КаталогЯдра; + + Построитель().СоздатьТочкуВхода( + Детальки(Массивы.ИзЭлементов("./tests/fixtures"), Новый Массив), + МенеджерВременныхФайлов, + Логирование.ПолучитьЛог("oscript.lib.oneunit.тесты"), + "// тестовая команда", + Параметры + ); + + ТекстСценария = СценарийПрогона(МенеджерВременныхФайлов); + + Ожидаем.Что(СтрНайти(ТекстСценария, КаталогЯдра), "Указанное ядро") + .Больше(0); + + Ожидаем.Что(СтрНайти(ТекстСценария, КаталогЯдраПоУмолчанию()), "Ядро по умолчанию не используется") + .Равно(0); + + МенеджерВременныхФайлов.Удалить(); + +КонецПроцедуры + +&Тест +Процедура ЯдроПоУмолчаниюНеЗависитОтТекущегоКаталога() Экспорт + + // Ядро по умолчанию отсчитывается от каталога построителя, а не от текущего каталога. + // На этом держится изоляция: изолированный набор прогоняется дочерним процессом уже + // внутри выбранного ядра, и своё ядро тот определяет по умолчанию - то есть тем же + // ядром, которым запущен сам. Текущий каталог там - каталог тестируемого проекта, + // и отсчёт от него увёл бы изолированный прогон на несуществующее ядро + + МенеджерВременныхФайлов = Новый МенеджерВременныхФайлов(); + МенеджерВременныхФайлов.БазовыйКаталог = МенеджерВременныхФайлов.СоздатьКаталог(); + + ИсходныйКаталог = ТекущийКаталог(); + КаталогиТестов = Массивы.ИзЭлементов( + ФС.НормализоватьПуть(ОбъединитьПути(ИсходныйКаталог, "tests", "fixtures")) + ); + + УстановитьТекущийКаталог(МенеджерВременныхФайлов.БазовыйКаталог); + + Попытка + + Построитель().СоздатьТочкуВхода( + Детальки(КаталогиТестов, Новый Массив), + МенеджерВременныхФайлов, + Логирование.ПолучитьЛог("oscript.lib.oneunit.тесты"), + "// тестовая команда" + ); + + Исключение + УстановитьТекущийКаталог(ИсходныйКаталог); + ВызватьИсключение; + КонецПопытки; + + УстановитьТекущийКаталог(ИсходныйКаталог); + + Ожидаем.Что(СтрНайти(СценарийПрогона(МенеджерВременныхФайлов), КаталогЯдраПоУмолчанию()), "Ядро по умолчанию") + .Больше(0); + + МенеджерВременныхФайлов.Удалить(); + +КонецПроцедуры + +&Тест +Процедура НесуществующееЯдроОтклоняетсяСразу() Экспорт + + // Промах в каталоге ядра иначе виден только дочернему процессу, а тот жалуется + // на несуществующую библиотеку - по такому сообщению до параметра не добраться + + МенеджерВременныхФайлов = Новый МенеджерВременныхФайлов(); + МенеджерВременныхФайлов.БазовыйКаталог = МенеджерВременныхФайлов.СоздатьКаталог(); + + Параметры = Запускатель().ПараметрыЗапуска(); + Параметры.КаталогЯдра = ОбъединитьПути(МенеджерВременныхФайлов.БазовыйКаталог, "ядра-тут-нет"); + + Описание = ""; + + Попытка + + Построитель().СоздатьТочкуВхода( + Детальки(Массивы.ИзЭлементов("./tests/fixtures"), Новый Массив), + МенеджерВременныхФайлов, + Логирование.ПолучитьЛог("oscript.lib.oneunit.тесты"), + "// тестовая команда", + Параметры + ); + + Исключение + Описание = ОписаниеОшибки(); + КонецПопытки; + + Ожидаем.Что(СтрНайти(Описание, "Каталог ядра прогона не найден"), "Сообщение об ошибке") + .Больше(0); + + МенеджерВременныхФайлов.Удалить(); + +КонецПроцедуры + #КонецОбласти #Область ТестыЗапускателяТестирования @@ -442,4 +576,23 @@ КонецФункции +Функция КаталогЯдраПоУмолчанию() + + Возврат ФС.НормализоватьПуть(ОбъединитьПути(ТекущийКаталог(), "src", "core")); + +КонецФункции + +// Точка входа загружает отдельный сценарий, в котором подключается ядро и запускается прогон. +Функция СценарийПрогона(МенеджерВременныхФайлов) + + Тексты = Новый Массив(); + + Для Каждого Файл Из НайтиФайлы(МенеджерВременныхФайлов.БазовыйКаталог, "*.os") Цикл + Тексты.Добавить(ПрочитатьФайл(Файл.ПолноеИмя)); + КонецЦикла; + + Возврат СтрСоединить(Тексты, Символы.ПС); + +КонецФункции + #КонецОбласти