Перем Тесты;
Перем ТекущийТест, фНаборВыполнен;
Перем _Результат, _СообщатьОПрогрессе;

// флаг эмуляции падения 1С, 
// в месте падения тест должен пользоваться спец. методов ЭмулироватьПадение1С
// Если флаг = 1, то вместо падения выдается сообщение и продолжение работы тестов останавливается !
// по умолчанию 0 - выключен. 
//
//	Используется в классах НаборТестов и ТестовыйСлучай
//
//Перем ФлагЭмуляцииПадения1С Экспорт; 
Перем _фОтключитьПропускТестов;

Перем _СписокПадений; // использую для передачи данных в другой результат

Процедура Конструктор()
	Тесты = СоздатьОбъект("СписокЗначений");
	_Результат= СоздатьОбъект("РезультатТеста");

	_СписокПадений = СоздатьОбъект("СписокЗначений");
КонецПроцедуры

Процедура ЗапуститьТесты() Экспорт
	Пока Тесты.РазмерСписка()>0 Цикл
		ТекущийТест = Тесты.ПолучитьЗначение(1);

		Тесты.УдалитьЗначение(1);
		Если _СообщатьОПрогрессе = 1 Тогда
        	// сообщение о пройденных тестах выдаю только в лог-файл, ИМХО так удобнее
	        _Результат.ЛогФайл.Сообщить(ТекущийТест.Описание());
		КонецЕсли;
		//Возможен запуск теста или вложенного набора тестов
		
		ТекущийТест.Запустить(_Результат, _фОтключитьПропускТестов);
		Если ТекущийТест.Завершен()=0 Тогда Возврат; КонецЕсли;
	КонецЦикла;
	фНаборВыполнен=1;
КонецПроцедуры

Процедура Запустить(Результат, фОтключитьПропуск, СообщатьОПрогрессе) Экспорт
	_фОтключитьПропускТестов=фОтключитьПропуск;
	Если ТипЗначенияСтр(Результат) = "РезультатТеста" Тогда
		// значит, нужно переписать данные о произошедших падениях
		Для ъ=1 По _СписокПадений.РазмерСписка() Цикл
			Ошибка = "";
			ПредставлениеТеста = _СписокПадений.ПолучитьЗначение(ъ, Ошибка);
			Результат.ДобавитьПадение(ПредставлениеТеста, Ошибка, "");
		КонецЦикла;
	КонецЕсли;

	_Результат=?(ТипЗначенияСтр(Результат)="РезультатТеста", Результат, _Результат);
	Если ПустоеЗначение(Результат) = 1 Тогда
		Результат = _Результат;
	КонецЕсли;
	_СообщатьОПрогрессе=СообщатьОПрогрессе;
	//_Результат.ОтметитьВремяЗапуска();
	фНаборВыполнен=0;
	ЗапуститьТесты();
КонецПроцедуры

Функция Результат() Экспорт
	Возврат _Результат;
КонецФункции

Функция Выполнен() Экспорт
	Если фНаборВыполнен=1 Тогда Возврат 1; КонецЕсли;
	Если ТекущийТест.Завершен()=0 Тогда Возврат 0; КонецЕсли;
	ЗапуститьТесты();
	Возврат фНаборВыполнен;
КонецФункции

Процедура ДобавитьТест(Тест) Экспорт

	Тесты.ДобавитьЗначение(Тест, ТипЗначенияСтр(Тест)+"."+Тест.ИмяМетода);
КонецПроцедуры

// если создание успешно, возвращает созданный объект
// иначе пустое значение неопределенного типа
//
Функция ПопыткаСоздатьОбъект(ИмяКласса, СообщениеОбОшибке) Экспорт
	Попытка
		Тест = СоздатьОбъект(ИмяКласса);
		Возврат Тест;
	Исключение
		СообщениеОбОшибке = ОписаниеОшибки();
		Попытка
			Модуль = СоздатьОбъект("ВыполняемыйМодуль");
			ОбъектИcключения = Модуль.ПолучитьИсключение();
			СообщениеОбОшибке = ОбъектИcключения;
		Исключение
		КонецПопытки;

        _Результат.ДобавитьПадение("Класс '"+ИмяКласса+"'", СообщениеОбОшибке, "");
        _СписокПадений.ДобавитьЗначение("Класс '"+ИмяКласса+"'", СообщениеОбОшибке);

		Возврат ПолучитьПустоеЗначение("");
	КонецПопытки;
КонецФункции	// ПопыткаСоздатьОбъект

// Возвращает
// 1  если это потомок класса Тестовый случай
// 0  если нет
// -1 если попытка создания класса завершилась неудачей
//
Функция ЭтоТест(ИмяКлассаИлиСамОбъектаКласса) Экспорт
	Если ТипЗначенияСтр(ИмяКлассаИлиСамОбъектаКласса) <> "Строка"  Тогда
		Тест = ИмяКлассаИлиСамОбъектаКласса;
	Иначе
		СообщениеОбОшибке = "";
		Тест = ПопыткаСоздатьОбъект(ИмяКлассаИлиСамОбъектаКласса, СообщениеОбОшибке);
		Если ПустоеЗначение(Тест) = 1 Тогда
			Возврат -1;
		КонецЕсли;
	КонецЕсли;

    Если ТипЗначенияСтр(Тест.ПолучитьБазовыйКласс("ТестовыйСлучай")) <> "ТестовыйСлучай" Тогда
        Возврат 0;
    КонецЕсли;

	Возврат 1;
КонецФункции

Процедура Добавить(ИмяКлассаИлиОбъектКласса, ИмяМетода) Экспорт
	СообщениеОбОшибке = "";     
	Если ТипЗначенияСтр(ИмяКлассаИлиОбъектКласса) <> "Строка" Тогда
		Тест = ИмяКлассаИлиОбъектКласса;
		ИмяКласса = ТипЗначенияСтр(ИмяКлассаИлиОбъектКласса);
	Иначе                           
		ИмяКласса = ИмяКлассаИлиОбъектКласса;
		Тест = ПопыткаСоздатьОбъект(ИмяКласса, СообщениеОбОшибке);
	КонецЕсли;

	Если ПустоеЗначение(Тест) = 1 Тогда
        Ошибка  =  "Создание класса '"+ИмяКласса+"' закончилось неудачей
				|	в тестировании класс не участвует
				|"+СообщениеОбОшибке;
        _Результат.ДобавитьПадение("Класс '"+ИмяКласса+"'", Ошибка, "");
        _СписокПадений.ДобавитьЗначение("Класс '"+ИмяКласса+"'", Ошибка);
		Возврат;
	КонецЕсли;
// ----------------------------------------------------------------------------
// 		TODO обязательно нужно проверить класс "ИмяКласса", что он является
// 		потомком класса "ТестовыйСлучай"
// 		Иначе добавление класса вылетит на следующей строке !!
// ----------------------------------------------------------------------------

    Если ЭтоТест(Тест) = 0 Тогда
        Ошибка  =  "Класс   '"+ИмяКласса+"' не является потомком класса ТестовыйСлучай
				|	в тестировании класс не участвует";
        _Результат.ДобавитьПадение("Класс '"+ИмяКласса+"'", Ошибка, "");
        _СписокПадений.ДобавитьЗначение("Класс '"+ИмяКласса+"'", Ошибка);
        Возврат;
    КонецЕсли;

	Тест.Инит(ИмяМетода);
	ДобавитьТест(Тест);
КонецПроцедуры

Функция ВсегоТестов() Экспорт
	Возврат Тесты.РазмерСписка();
КонецФункции

// ---------------------------------------  ---------------------------------
процедура ПриЗаписи_ФлагЭмуляцииПадения1С(НовыйФлагЭмуляцииПадения1С)// Экспорт
	
	ФлагЭмуляцииПадения1С = НовыйФлагЭмуляцииПадения1С;
	Для ъ=1 По Тесты.РазмерСписка() Цикл
		Тесты.ПолучитьЗначение(ъ).ФлагЭмуляцииПадения1С = НовыйФлагЭмуляцииПадения1С;
	КонецЦикла;
КонецПроцедуры // ПриЗаписи_ФлагЭмуляцииПадения1С