Трассировка стека в Powershell нарушена? - PullRequest
1 голос
/ 24 августа 2010

Я пишу простой модуль модульного теста в PowerShell

. Я разработал модуль так, чтобы его функции assert принимали блок скрипта в качестве параметра, чтобы позволить ему запускать код из функции assert иобрабатывать любые исключения, которые вызываются как провал теста.

Если тесты не пройдены, я хочу вернуть строку в модульный тест, в котором тест не пройден.Мой план состоял в том, чтобы сделать это путем получения трассировки стека (Get-PSCallStack) в начале каждого метода assert и использовать информацию для второго стекового фрейма, который, как я полагаю, должен соответствовать строке, где была вызвана функция assert.

На практике я обнаружил, что информация, которую вернул PowerShell, показалась неверной.Второй стековый фрейм относится к правильному файлу, как и ожидалось, но всегда дает номер строки, с которой я вызвал Get-PSCallStack в методе assert.Иногда это число может быть даже больше, чем количество строк в указанном файле (т. Е. Местоположение задается как «ScriptFile.ps1 строка 88», но файл содержит только 20 строк).

Есть ли проблема страссировка стека в powershell или есть что-то, чего я здесь не понимаю?

Редактировать

По запросу я публикую пример, который должен давать такие же результаты

Tester.ps1

#File 1 (Tester.ps1)
#Creates the tester object

$tester = (New-Object PSObject);

$tester | Add-Member -MemberType ScriptMethod -Name AssertTrue -Value {
    param($expression);

    $stackFrame = (GEt-PSCallStack)[1];

    try{
        $result = &$expression;
        if($result -eq $true){
            $this.LogPass();
        }else{
            $this.LogFailure("Evaluation Failed expected ""$true"" got ""$false""", $stackFrame);
        }
    }catch [Exception]{
        $this.LogFailure("Unexpected exception encountered", $stackFrame);
    }
}

$tester | Add-Member -MemberType ScriptMethod -Name LogPass -Value {
    #Do nothing
};

$tester | Add-Member -MemberType ScriptMethod -Name LogFailure -Value {
    param($message, $stackFrame);
    "Failure Encounterd";
    "Command: $($stackFrame.Command)"
    "Location: $($stackFrame.Location)";
    "Message: $message";
}

return $tester;

TestCase.ps1

#File 2 (TestCase.ps1)
#Runs the tests using the tester object

$tester = &(Resolve-Path "Tester.ps1");

function TestFailure($tester){
    $expression = {$false};
    $tester.AssertTrue($expression);
}

TestFailure($tester);

Актив вызывается в 7-й строке TestCase.ps1, а стек вызовов захватывается в 9-й строке Tester.ps1.

Это печатает

Failure Encounterd
Command: TestFailure
Location: Tester.ps1: Line 9
Message: Evaluation Failed expected "True" got "False"

Команда верна, но и файл, и строка неверны

Следующий кадр трассировки стека правильно описывает, где TestFailure ()вызывается с его местоположением "TestCase.ps1: строка 11"

1 Ответ

2 голосов
/ 24 августа 2010

Это не используемая вами функция assert , это блок сценария assert , используемый в качестве «функции-члена».Но это все еще блок скрипта.

В соответствии с этой сообщенной проблемой: https://connect.microsoft.com/PowerShell/feedback/details/531086/depending-on-how-you-invoke-a-script-block-the-invocation-details-may-not-be-available-from-inside-the-script-block#

что-то не так с вызовом Get-PSCallStack из блоков скрипта.Итак, ответ на ваш вопрос, вероятно, таков: да, это проблема PowerShell.

Ну, я бы порекомендовал вам использовать функции.Я переработал ваши скрипты для использования функций (грязная версия, плохие имена и т. Д.), И они работают должным образом:

#File 1 (Tester.ps1)
#Creates the tester object

function AssertTrue {
    param($expression);

    $stackFrame = (Get-PSCallStack)[1]

    try{
        $result = . $expression;
        if($result -eq $true){
            LogPass
        }else{
            LogFailure ("Evaluation Failed expected ""$true"" got ""$false""") $stackFrame
        }
    }catch [Exception]{
        LogFailure "Unexpected exception encountered" $stackFrame
    }
}

function LogPass {
    #Do nothing
}

function LogFailure {
    param($message, $stackFrame);
    "Failure Encounterd";
    "Command: $($stackFrame.Command)"
    "Location: $($stackFrame.Location)";
    "Message: $message";
}

И

#File 2 (TestCase.ps1)
#Runs the tests using the tester object

. (Resolve-Path "Tester.ps1");

function TestFailure {
    $expression = {$false};
    AssertTrue $expression
}

TestFailure
...