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

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

// флаг эмуляции падения 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);
КонецПроцедуры

Процедура ПроверитьРавенствоДлинныхСтрок(Строка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(Значение);
КонецПроцедуры

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

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

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

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

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

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

Функция _ПолучитьКод() Экспорт
	Предупреждение("Вызвана _ПолучитьКод");
	Возврат Описание();
КонецФункции

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

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

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

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