Перем ИмяМетода Экспорт;

Перем сохрОптимизация, сохрПроверкаТипов, сохрОтладка; // сохранение/восстановление настроек

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

Функция Конт(Конт) Возврат Конт; КонецФункции
Функция Сам() Возврат Конт(Контекст); КонецФункции
           
// виртуальный метод для переопределения в классах-наследниках
// вызывается всегда перед запуском тестирования теста
// в нем не должно быть исключений (иначе вся система тестирования не будет работать)
//	ВАЖНО: при переопределении метода в классе наследнике
// НЕ забывать вызывать метод из базового класса
//
Процедура Сетап() Экспорт
	// virtual method

	// сохранение настроек
	MetaInfoClasses.ПолучитьТекУстановки(сохрОптимизация, сохрПроверкаТипов, сохрОтладка);
КонецПроцедуры

// виртуальный метод для переопределения в классах-наследниках
// вызывается всегда после тестирования теста
//	неважно, удачно или неудачно завершился тест
// в нем не должно быть исключений (иначе вся система тестирования не будет работать)
//	ВАЖНО: при переопределении метода в классе наследнике
// НЕ забывать вызывать метод из базового класса
//
Процедура Сброс() Экспорт
	// virtual method
	
	// восстановление настроек
	MetaInfoClasses.УстановитьТекУстановки(сохрОптимизация, сохрПроверкаТипов, сохрОтладка);
КонецПроцедуры

Функция Описание() Экспорт
	Возврат ТипЗначенияСтр(Сам())+"::"+ИмяМетода;
КонецФункции
//--------------------------------------------

Функция Завершен() Экспорт
	Возврат 1;
КонецФункции
//--------------------------------------------
   
// виртуальный метод для переопределения в классах-наследниках
// запуск тестирования
//	ВАЖНО: при переопределении метода в классе наследнике
// НЕ забывать вызывать метод из базового класса
//
Процедура Запустить(Результат, фОтключитьПропуск) Экспорт
	_фПропускТестаОтключен=фОтключитьПропуск;
	Сам().Сетап();

	Длг = СоздатьОбъект("Делегат");
	Длг.ОпределитьТип(0, 0);

	Состояние(Описание());
	Попытка
		Длг.Добавить(Сам(), ИмяМетода);
//Сообщить("Перед вызовом делегата = "+ИмяМетода);		
//Предупреждение("Перед вызовом делегата = "+ИмяМетода);		
		Длг.Вызвать();
//Сообщить("После вызова делегата = "+ИмяМетода);		
//Предупреждение("После вызова делегата = "+ИмяМетода);		
		Результат.ДобавитьУспех();
	Исключение
//Сообщить("Исключение при вызове делегата = "+ИмяМетода);		
//Предупреждение("Исключение при вызове делегата = "+ИмяМетода);		
		Ошибка=ОписаниеОшибки();
		Результат.ДобавитьПадение(Описание(), Ошибка, Сам().ПолучитьИсключение());
	КонецПопытки;

//Предупреждение("Перед сбросом = "+ИмяМетода);		
//Сообщить("Перед сбросом = "+ИмяМетода);		
	Сам().Сброс();
//Предупреждение("После сброса = "+ИмяМетода);		
	Состояние("");
КонецПроцедуры

Процедура Инит(ИмяТестовогоМетода) Экспорт
	ИмяМетода = ИмяТестовогоМетода;
КонецПроцедуры

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

Процедура Assert(Значение) Экспорт
	Если ПустоеЗначение(Значение)=1 Тогда
		СтрокаИсключения = "<"+Значение+"> - ложно, а хотели истину.";
		ВМ = СоздатьОбъект("ВыполняемыйМодуль");
		ВМ.ВыброситьИскл(СтрокаИсключения, СтрокаИсключения);
	КонецЕсли;
КонецПроцедуры

Процедура ПроверитьИстину(Значение) Экспорт
	Assert(Значение);
КонецПроцедуры

Процедура AssertNot(Значение) Экспорт
	Если ПустоеЗначение(Значение)=0 Тогда
		ВМ = СоздатьОбъект("ВыполняемыйМодуль");
		СтрокаИсключения = "<"+Значение+"> - истинно, а хотели ложь";
		ВМ.ВыброситьИскл(СтрокаИсключения, СтрокаИсключения);
	КонецЕсли;
КонецПроцедуры

Процедура ПроверитьЛожь(Значение) Экспорт
	AssertNot(Значение);
КонецПроцедуры

Процедура AssertEquals(Значение1, Значение2) Экспорт
	Если Значение1 <> Значение2 Тогда
		ВМ = СоздатьОбъект("ВыполняемыйМодуль");
		СтрокаИсключения = "<"+Значение1+"> не равно <"+Значение2+">, а хотели, чтоб было равно.";
		ВМ.ВыброситьИскл(СтрокаИсключения, СтрокаИсключения);
	КонецЕсли;
КонецПроцедуры

Процедура ПроверитьРавенство(Значение1, Значение2) Экспорт
	AssertEquals(Значение1, Значение2);
КонецПроцедуры

Процедура AssertEqualsWithPrecision(Значение1, Значение2, Точность) Экспорт
	AssertEquals(Окр(Значение1, Точность), Окр(Значение2, Точность));
КонецПроцедуры

Процедура ПроверитьРавенствоСТочностью(Значение1, Значение2, Точность) Экспорт
	AssertEqualsWithPrecision(Значение1, Значение2, Точность);
КонецПроцедуры

Процедура AssertNotEquals(Значение1, Значение2) Экспорт
	Если Значение1 = Значение2 Тогда
		ВМ = СоздатьОбъект("ВыполняемыйМодуль");
		СтрокаИсключения = "<"+Значение1+"> равно <"+Значение2+">, а хотели, чтоб было не равно.";
		ВМ.ВыброситьИскл(СтрокаИсключения, СтрокаИсключения);
	КонецЕсли;
КонецПроцедуры

Процедура ПроверитьНеравенство(Значение1, Значение2) Экспорт
	AssertNotEquals(Значение1, Значение2);
КонецПроцедуры


Процедура AssertFail(Объект, Метод, Параметр) Экспорт
	Длг = СоздатьОбъект("Делегат");
	Длг.ОпределитьТип(1, 0);
	Длг.Добавить(Объект, Метод);

	Упал=0;
	Попытка
		Длг.Вызвать(Параметр);
	Исключение
		Упал=1;
	КонецПопытки;

	Если Упал=0 Тогда
		ВМ = СоздатьОбъект("ВыполняемыйМодуль");
		СтрокаИсключения = "Хотели исключения, а его не было.";
		ВМ.ВыброситьИскл(СтрокаИсключения, СтрокаИсключения);
	КонецЕсли;

КонецПроцедуры

Процедура ПроверитьИсключение(Объект, Метод, Параметр) Экспорт
	AssertFail(Объект, Метод, Параметр);
КонецПроцедуры

Процедура ПроверитьРавенствоДлинныхСтрок(Строка1, Строка2, НеУчитыватьРазноеКоличествоСтрок = 0) Экспорт
	Если Строка1 <> Строка2 Тогда
	    КолСтрок = СтрКоличествоСтрок(Строка1);
		Если НеУчитыватьРазноеКоличествоСтрок = 1 Тогда
			КолСтрок = Мин(СтрКоличествоСтрок(Строка1), СтрКоличествоСтрок(Строка2))
		Иначе
			ПроверитьРавенство(СтрКоличествоСтрок(Строка1), СтрКоличествоСтрок(Строка2));
		КонецЕсли;
		Для к=1 По КолСтрок Цикл
			Стр1 = СтрПолучитьСтроку(Строка1, к);
			Стр2 = СтрПолучитьСтроку(Строка2, к);
			ПроверитьРавенство(к+": "+Стр1, к+": "+Стр2);

		КонецЦикла;
	КонецЕсли;
КонецПроцедуры

Процедура ПроверитьБольше(Значение1, Значение2) Экспорт
	Если Значение1 <= Значение2 Тогда
        ВМ = СоздатьОбъект("ВыполняемыйМодуль");
		СтрокаИсключения = "<"+Значение1+"> <= <"+Значение2+">, а хотели, чтоб было больше.";
		ВМ.ВыброситьИскл(СтрокаИсключения, СтрокаИсключения);
	КонецЕсли;
КонецПроцедуры

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

Процедура ПроверитьБольшеИлиРавно(Значение1, Значение2) Экспорт
	Если Значение1 < Значение2 Тогда
        ВМ = СоздатьОбъект("ВыполняемыйМодуль");
		СтрокаИсключения = "<"+Значение1+"> меньше <"+Значение2+">, а хотели, чтоб было больше или равно.";
		ВМ.ВыброситьИскл(СтрокаИсключения, СтрокаИсключения);
	КонецЕсли;
КонецПроцедуры

Процедура ПроверитьМеньшеИлиРавно(Значение1, Значение2) Экспорт
	Если Значение1 > Значение2 Тогда
        ВМ = СоздатьОбъект("ВыполняемыйМодуль");
		СтрокаИсключения = "<"+Значение1+"> больше <"+Значение2+">, а хотели, чтоб было меньше или равно.";
		ВМ.ВыброситьИскл(СтрокаИсключения, СтрокаИсключения);
	КонецЕсли;
КонецПроцедуры

// в сравниваемой таблице количество строк или больше, или равно количеству строк в исходной таблице,
//
Процедура ПроверитьРавенствоТаблиц(ИсходнаяТаблица, СравниваемаяТаблица, ИндексноеВыражение1, ИндексноеВыражение2) Экспорт
    ИмяКлюча = "ПроверитьТаблицы_Ключ";

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

	СравниваемаяТаблица.КоличествоСтрок(ИсходнаяТаблица.КоличествоСтрок()); // сначала обрежу таблицу

	ТабРазности = СоздатьОбъект("ИндексированнаяТаблица");
	ТабРазности.Загрузить(ИсходнаяТаблица);
	ТабРазности.ДобавитьИндекс(ИмяКлюча, ИндексноеВыражение1);

	ТабРазности2 = СоздатьОбъект("ИндексированнаяТаблица");
	ТабРазности2.Загрузить(СравниваемаяТаблица);
	ТабРазности2.ДобавитьИндекс(ИмяКлюча, ИндексноеВыражение2);

	ТабРазности.Разность(ТабРазности2, ИмяКлюча, ИмяКлюча);

	Если ТабРазности.КоличествоСтрок() <> 0 Тогда
        ВМ = СоздатьОбъект("ВыполняемыйМодуль");
		СтрокаИсключения = "Найдены различия между исходной и сравниваемой таблицами, а хотели, чтоб было они были равны.";
		ВМ.ВыброситьИскл(СтрокаИсключения, СтрокаИсключения);
	КонецЕсли;
КонецПроцедуры

Процедура ПроверитьПустоеЗначение(Значение) Экспорт
	Assert(Значение);
КонецПроцедуры

Процедура ПроверитьНеПустоеЗначение(Значение) Экспорт
	AssertNot(Значение);
КонецПроцедуры

// проверить исключение для методов с неопределенным числом параметров !!
// c использованием Делегата, поэтому нужен флаг функции
// имхо более удобен метод ПроверитьИсключениеДляЛюбогоМетода2 (без указания флага функции/процедуры)
//
// Отключена, лучше использовать другую - у нее меньше ограничений.
Процедура _ПроверитьИсключениеДляЛюбогоМетода(Объект, ИмяМетода, ФлагФункции)
	
	СписокПараметров = Сам().ПолучитьСписокПараметров("ПроверитьИсключениеДляЛюбогоМетода");
	
	Длг = СоздатьОбъект("Делегат");
	Длг.ОпределитьТип(СписокПараметров.РазмерСписка(), ФлагФункции);
	Длг.Добавить(Объект, ИмяМетода);
    
	фБезПараметров = ?(СписокПараметров.РазмерСписка() = 0, 1, 0);
	
	Если фБезПараметров = 0 Тогда
		ТекстМодуля = "";
		Для к=1 По СписокПараметров.РазмерСписка() Цикл
			ТекстМодуля = ТекстМодуля + "Перем Параметр"+Строка(к) +" Экспорт;"+РазделительСтрок;
		КонецЦикла;
		ТекстМодуля = ТекстМодуля+"
		|Процедура Добавить(Номер, Параметр) Экспорт"+РазделительСтрок;
		
		Для к=1 По СписокПараметров.РазмерСписка() Цикл
			ТекстМодуля = ТекстМодуля + "Если Номер = "+Строка(к) +" Тогда
			|	Параметр"+Строка(к)+" = Параметр;
			|КонецЕсли;"+РазделительСтрок;
		КонецЦикла;
		
		ТекстМодуля = ТекстМодуля + "КонецПроцедуры"+РазделительСтрок;
		
		ТекстМодуля = ТекстМодуля + "Функция Вызвать(Длг, ОбъектИсключения) Экспорт"+РазделительСтрок;
		ТекстМодуля = ТекстМодуля + "//Сообщить(Параметр1);"+РазделительСтрок;
		ТекстМодуля = ТекстМодуля + "Попытка
		|	Длг.Вызвать(";
		
		Для к=1 По СписокПараметров.РазмерСписка()-1 Цикл
			ТекстМодуля = ТекстМодуля + "Параметр"+Строка(к)+",";
		КонецЦикла;
		Для к=СписокПараметров.РазмерСписка() По СписокПараметров.РазмерСписка() Цикл
			ТекстМодуля = ТекстМодуля + "Параметр"+Строка(к)+");
			|	Возврат 0;"+РазделительСтрок;		
		КонецЦикла;
		
		ТекстМодуля = ТекстМодуля + "Исключение 
		|	ВМ = СоздатьОбъект(""ВыполняемыйМодуль"");
		|	ОбъектИсключения = ВМ.ПолучитьИсключение();
		|	Возврат 1; 
		|КонецПопытки;
		|
		|КонецФункции"+РазделительСтрок;
	КонецЕсли;

	Упал=0;
	Попытка                   
		Если фБезПараметров = 1 Тогда
			Длг.Вызвать();
		Иначе
			ВМ = СоздатьОбъект("ВыполняемыйМодуль");
			ВМ.УстановитьМодуль(ТекстМодуля);
			фРез = ВМ.КомпилироватьМодуль();
			фРез = ВМ.ВыполнитьМодуль();
			
			Для к=1 По СписокПараметров.РазмерСписка() Цикл
				ВМ.Добавить(к, СписокПараметров.ПолучитьЗначение(к));
			КонецЦикла;
			
			ОбъектИсключения = "";
			фБылоИсключение = ВМ.Вызвать(Длг, ОбъектИсключения);
			               
			Если фБылоИсключение = 1 Тогда
				Упал = 1;
			КонецЕсли;
		КонецЕсли;
	Исключение
		Упал=1;
	КонецПопытки;

	Если Упал=0 Тогда
		ВМ = СоздатьОбъект("ВыполняемыйМодуль");
		СтрокаИсключения = "Хотели исключения, а его не было.";
		ВМ.ВыброситьИскл(СтрокаИсключения, СтрокаИсключения);
	КонецЕсли;

КонецПроцедуры
         
Функция МодульВызоваМетода(Объект, ИмяМетода, ЧислоПараметров)
	ТекстМодуля = "";
	Для ъ=1 По ЧислоПараметров  Цикл
		ТекстМодуля = ТекстМодуля + "Перем Параметр"+ъ+" Экспорт;"+РазделительСтрок;
	КонецЦикла;
	
	ТекстМодуля = ТекстМодуля + "
	|Процедура Добавить(Номер, Параметр) Экспорт
	|";
	
	Для ъ=1 По ЧислоПараметров Цикл
		ТекстМодуля = ТекстМодуля + "Если Номер = "+ ъ +" Тогда Параметр"+ъ+" = Параметр; КонецЕсли;"+РазделительСтрок;
	КонецЦикла;
	
	ТекстМодуля = ТекстМодуля +
	"КонецПроцедуры
	|";
	
	стрПараметры = "";
	Для ъ=1 По ЧислоПараметров Цикл
		стрПараметры = стрСоединить(стрПараметры, "Параметр"+ъ);
	КонецЦикла;
	
	ТекстМодуля = ТекстМодуля + "
	|Функция Вызвать(Объект, ОбъектИсключения) Экспорт
	|	//Сообщить(Параметр1);
	|	Попытка
	|		" + ?(ПустоеЗначение(Объект)=0, "Объект.", "") + ИмяМетода+"(" + стрПараметры + ");
	|		Возврат 0;
	|	Исключение 
	|	КонецПопытки;
	|
	|	ВМ = СоздатьОбъект(""ВыполняемыйМодуль"");
	|	ОбъектИсключения = ВМ.ПолучитьИсключение();
	|	Возврат 1; 
	|КонецФункции
	|";
	//ТекстМодуля = ТекстМодуля + "
	//|Процедура Вызвать(Объект) Экспорт
	//|		" + ?(ПустоеЗначение(Объект)=0, "Объект.", "") + ИмяМетода+"(" + стрПараметры + ");
	//|КонецПроцедуры
	//|";
	
	ВМ = СоздатьОбъект("ВыполняемыйМодуль");
	ВМ.УстановитьМодуль(ТекстМодуля);
	Возврат ВМ;
КонецФункции

// проверить исключение для методов с неопределенным числом параметров !!
// Объект может быть пустым значением, тогда это просто вызов глобального метода
// Например, таким образом удобно тестировать метод СоздатьОбъект("");
//
Процедура ПроверитьИсключениеДляЛюбогоМетода(Объект, ИмяМетода) Экспорт
	
	спПараметры = Сам().ПолучитьСписокПараметров("ПроверитьИсключениеДляЛюбогоМетода");
	ЧислоПараметров = спПараметры.РазмерСписка();

	ВМ = МодульВызоваМетода(Объект, ИмяМетода, ЧислоПараметров);

	Упал=0;
	Попытка                   
		фРез = ВМ.КомпилироватьМодуль();
		фРез = ВМ.ВыполнитьМодуль();
		
		Для ъ=1 По ЧислоПараметров Цикл
			ВМ.Добавить(ъ, спПараметры.ПолучитьЗначение(ъ));
		КонецЦикла;
		
		ОбъектИсключения = "";
		фБылоИсключение = ВМ.Вызвать(Объект, ОбъектИсключения);
		               
		Если фБылоИсключение = 1 Тогда
			Упал = 1;
		КонецЕсли;
		//ВМ.Вызвать(Объект);
	Исключение
		Упал=1;
	КонецПопытки;

	Если Упал=0 Тогда
		ВМ = СоздатьОбъект("ВыполняемыйМодуль");
		СтрокаИсключения = "Хотели исключения, а его не было.";
		ВМ.ВыброситьИскл(СтрокаИсключения, СтрокаИсключения);
	КонецЕсли;

КонецПроцедуры

Функция _ПолучитьКод() Экспорт
	Предупреждение("Вызвана _ПолучитьКод");
	Возврат Описание();
КонецФункции
    
// метод работает только в 2.5
Процедура ПроверитьНастройку(Наименование, Значение) Экспорт
	Попытка
		ОБ = СоздатьОбъект("УправлениеНастройками");
	Исключение
		Возврат;
	КонецПопытки;
	
	Флаг = ОБ.Получить(Наименование);
	Если Флаг <> Значение Тогда
		Если Значение = 0 Тогда
			Сам().ПропуститьТест(, "Настройка <"+Наименование+"> включена, а должна быть выключена");
		Иначе
			Сам().ПропуститьТест(, "Настройка <"+Наименование+"> выключена, а должна быть включена");
		КонецЕсли;
	КонецЕсли;
КонецПроцедуры	// ПроверитьНастройку
