Снегопат
https://snegopat.ru/forum/

Исключения (exceptions) и их отлов в скриптах
https://snegopat.ru/forum/viewtopic.php?f=3&t=54
Страница 1 из 4

Автор:  kuntashov [ 31 окт 2011, 16:00 ]
Заголовок сообщения:  Исключения (exceptions) и их отлов в скриптах

Всем привет!

Достаточно много возился в эти выходные со скриптами на 29 релизе (впрочем, пробовал и предыдущие), столкнулся с такой неприятной штукой.

Если при вызове метода/макроса (далее - просто метод) одного скрипта из другого скрипта в вызываемом методе вызвано исключение (брошено явно или неявно), то в вызывающем методе это исключение при помощи конструкции try {} catch (e) {} никак не поймать :(

В итоге оно всплывает на самый верх и нам всплывает стандартное окно с исключением и предложением запустить отладчик.

Кто-нибудь сталкивался с этим? Нашли какое-нибудь решение?

Саша, не подскажешь, есть ли возможность поймать исключение в описанной ситуации?

Для того, чтобы воспроизвести ситуацию прилагаю код простейших скриптов:

lib.js - скрипт, чей метод вызывается из другого скрипта

Код:
$engine JScript
$uname testExceptionsLib

function throwErrorFunction()
{
    throw "Excepiton from testExceptionsLib.throwErrorFunction()";
}

function macrosThrowErrorMacros()
{
    throw "Excepiton from testExceptionsLib.throwErrorMacros()";
}


app.js - скрипт, в макросе которого вызываем метод из lib.js и пытаемся обработать его исключение

Код:
$engine JScript
$uname testExceptionsApp

var lib = addins.byUniqueName("testExceptionsLib");

function macrosИсключениеПриВызовеФункции()
{
    try
    {
        lib.object.throwErrorFunction();
    }
    catch (e)
    {
        Message("Gotcha: " + e.text);
    }
}

function macrosИсключениеПриПрограммномВызовеМакроса()
{
    try
    {
        lib.invokeMacros("ThrowErrorMacros");
    }
    catch (e)
    {
        Message("Gotcha: " + e.text);
    }
}

p.s.
В порыве экспериментов я начерно портировал JsUnit (http://jsunit.net) под Снегопат и даже "нарисовал" простейший запускатель тестов, и оно даже работает, за исключением того, что первый же сломавшийся тест останавливает выполнение всех тестов из-за озвученной проблемы (assert'ы бросают исключения).

Автор:  artbear [ 31 окт 2011, 16:25 ]
Заголовок сообщения:  Re: Исключения (exceptions) и их отлов в скриптах

kuntashov писал(а):
В порыве экспериментов я начерно портировал JsUnit (http://jsunit.net) под Снегопат и даже "нарисовал" простейший запускатель тестов, и оно даже работает, за исключением того, что первый же сломавшийся тест останавливает выполнение всех тестов из-за озвученной проблемы (assert'ы бросают исключения).

А я в свое время пару часов попытался портировать, но не получилось и бросил :)
Жду код.

Автор:  kuntashov [ 31 окт 2011, 21:01 ]
Заголовок сообщения:  Re: Исключения (exceptions) и их отлов в скриптах

artbear писал(а):
А я в свое время пару часов попытался портировать, но не получилось и бросил :)
Жду код.


Как падучесть поборю, закоммичу. Сейчас очень часто падает, потому что до конца не отладил еще: на одном духу без единого запуска настрочил код, а потом стал запускать и последовательно исправлять ошибки.

Сейчас запускается, но почему-то регулярно в произвольные моменты падает. Но ничего, мы его обуздаем :)

Автор:  kuntashov [ 31 окт 2011, 21:03 ]
Заголовок сообщения:  Re: Исключения (exceptions) и их отлов в скриптах

Александру: покопался и инете, ничего путного не нашел, единственное, что теоретически может пригодиться (если дело все-таки во внутренностях Снегопата):

http://stackoverflow.com/questions/3145 ... atchinvoke

Автор:  artbear [ 01 ноя 2011, 07:24 ]
Заголовок сообщения:  Re: Исключения (exceptions) и их отлов в скриптах

kuntashov писал(а):
Как падучесть поборю, закоммичу.

Выложил бы здесь, поиграться :)
ЗЫ перед тестированием не могу устоять :)

Автор:  kuntashov [ 06 ноя 2011, 22:48 ]
Заголовок сообщения:  Re: Исключения (exceptions) и их отлов в скриптах

Нашел обход проблемы с перехватом исключений.
Не очень красивый, конечно, но зато работает.

Для решения проблемы мы в скрипт lib.js добавляем возможность подписки на возникающие исключения следующим образом (в дополнение к коду, цитируемому в топикстартере):

Код:
function SetErrorHandler(errorHandler)
{
    ErrorHandler = errorHandler;
}

function throwError(e)
{
    if (ErrorHandler)
    {
        ErrorHandler.call(null, e);   
        //ErrorHandler(e);   
        return e;
    }

    throw e;
}


И везде в коде, где раньше использовался оператор throw e заменяем его на вызов throwError(e):

Код:
function macrosThrowErrorMacros()
{
    throw "Excepiton from testExceptionsLib.throwErrorMacros()";
}


А в app.js мы подписываемся на исключения следующим образом:

Код:
var lib = addins.byUniqueName("testExceptionsLib");
lib.object.SetErrorHandler(function(e) { throw e});


Все, теперь явно брошенные в lib.js исключения будут ловиться при помощи конструкции try{}catch(e){} без проблем.

Автор:  kuntashov [ 06 ноя 2011, 22:56 ]
Заголовок сообщения:  Re: Исключения (exceptions) и их отлов в скриптах

artbear писал(а):
Выложил бы здесь, поиграться :)
ЗЫ перед тестированием не могу устоять :)


Выкладываю поиграться в бранч jsunit-port.

Единственное, она требует версии метода require() с моими последними правками (сделал, чтобы require() работал также, как $addin). Вот его код:

Код:
// Загрузить скрипт-библиотеку по имени файла или полному пути.
// Возвращает объект, предоставляющий доступ ко всем публичным
// функциям и переменным скрипта filename, аналогично директиве $addin.
function require(filename)
{
    var fullPath = filename;
   
    /* Задан полный путь или уникальное имя скрипта?
     * Проверяем по наличию указания буквы диска в начале пути
     * или двойного слеша (при адресации скрипта на сетевом ресурсе).
     */
   
    var isFullPath = fullPath.match(/^(\w\:|\\\\)/);
   
    /* Если задано только имя файла, то ищем скрипт-библиотеку по имени файла
     * в каталоге Scripts\Libs каталога Снегопата.
     * TODO: Нужен ли "правильный" алгоритм поиска библиотеки, в рабочем каталоге
     * и в путях, прописанных в переменной среды PATH?
     */
   
    if (!isFullPath)
    {
        var mainFolder = profileRoot.getValue("Snegopat/MainFolder");
        var f = v8New("Файл", mainFolder + "scripts\\Libs\\" + filename);
       
        if (!f.Существует() || !f.ЭтоФайл())
            throw "require: Не найден скрипт " + filename;
           
        fullPath = f.ПолноеИмя;
    }
     
    /* Формируем полный путь загрузки скрипта,
     * включающий в себя протокол.
     */
     
    var fullLoadString = "script:" + fullPath;
     
    /* Проверяем, не загружен ли скрипт уже (по полному пути)
     * и загружаем, если это не так.
     */
   
    var lib = addins.byFullPath(fullLoadString);
   
    if (!lib)
    {
        /* Среди групп аддинов первого уровня ищем группу для
         * скриптов-библиотек. Если такой группы нет, то создадим ее.
         */
       
        var libGroupName = "Подгружаемые библиотеки";       
        var libGroup = addins.root.child;               
        var libFound = false;
       
        while (libGroup)
        {
            if (libGroup.name == libGroupName)
            {
                libFound = true;
                break
            }
           
            libGroup = libGroup.next;
        }
       
        if (!libFound)
            libGroup = addins.root.addGroup(libGroupName);
           
        // Загружаем скрипт.
        try
        {
            lib = addins.loadAddin(fullLoadString, libGroup);
        }
        catch(e)
        {
            Message("require: Скрипт-библиотека не загружен: " + fullPath);
            // Пробрасываем исключение наверх.
            throw e;
        }
    }
       
   // require() должен вести себя как и деректива $addin
   return lib.object;   
}


Пример теста в Tests/Automated.
Пока работает только "Запустить все тесты".

Что не работает и надо сделать в первую очередь:

1. assign'ы для 1Совских объектов (теперь благодаря to1CValue это реально).
2. нормальный трейсинг (сейчас сделаны заглушки, надо бы вообще общий скрипт-библиотеку Tracer сделать)
3. прогресс-бар
4. примеры, документация, как пользоваться

Автор:  artbear [ 07 ноя 2011, 07:56 ]
Заголовок сообщения:  Re: Исключения (exceptions) и их отлов в скриптах

kuntashov писал(а):
Выкладываю поиграться в бранч jsunit-port.

Что не работает и надо сделать в первую очередь:

1. assign'ы для 1Совских объектов (теперь благодаря to1CValue это реально).
2. нормальный трейсинг (сейчас сделаны заглушки, надо бы вообще общий скрипт-библиотеку Tracer сделать)

Расшифруй по 1 и 2.
ассигны и трейсинг - это что?

Автор:  kuntashov [ 07 ноя 2011, 08:32 ]
Заголовок сообщения:  Re: Исключения (exceptions) и их отлов в скриптах

1. Прошу прощения, assert, конечно же, опечатался, да еще и в русской транскрипции )) сейчас методы работают для js-объектов, нужны методы assertValueTable (для таблицы значений), assert1CArray (для массива 1С), assertValueList, assertMap (для соответствия), assertStructure (для структуры) и т.п.

2. Трейсинг: вывод подробной информации о возникающих исключениях. jsUnitCore собирает достаточно подробную инфу об исключениях, включая стек вызовов, их надо бы выводить в случае возникновения ошибок.
Сейчас трассировка выводится в окно сообщений без подробностей. В идеале хотелось бы выводить сообщения об ошибках в свое окно (например, в поле табличного документа или в поле хтмл), с раскраской сообщений, с возможностью добавления гиперссылок (чтобы по клику на ошибке открывать в редакторе скрипт, в котором возникла ошибка) и т.п.

Автор:  artbear [ 07 ноя 2011, 08:45 ]
Заголовок сообщения:  Re: Исключения (exceptions) и их отлов в скриптах

kuntashov писал(а):
Выкладываю поиграться в бранч jsunit-port.

Единственное, она требует версии метода require() с моими последними правками (сделал, чтобы require() работал также, как $addin). Вот его код:

Пример теста в Tests/Automated.
Пока работает только "Запустить все тесты".

Если отдельно загружать и тестировать каталоги Tests/Automated и Tests/Exceptions, то тесты проходят,
но если загружать весь каталог Tests, то при тестировании через "Запустить все тесты" выдаются ошибки
Цитата:
'constructor' - есть null или не является объектом

и выдается окно ошибки
Если далее нажать "Пропустить отладку", то в окне сообщений все-таки появляется
Цитата:
Тест testExampleTestCase::TestSuccessfulTest выполнен успешно
Тест testExampleTestCase::TestFailedTest провалился (assertion failed)

ЗЫ исправление для require сделано.

Страница 1 из 4 Часовой пояс: UTC + 3 часа
Powered by phpBB® Forum Software © phpBB Group
http://www.phpbb.com/