内容

名称

TAP::Parser - 解析 TAP 输出

版本

版本 3.44

概要

use TAP::Parser;

my $parser = TAP::Parser->new( { source => $source } );

while ( my $result = $parser->next ) {
    print $result->as_string;
}

描述

TAP::Parser 旨在对 TAP 输出进行正确的解析。有关如何通过此模块运行测试的示例,请参见简单的测试程序 examples/

有一个专门用于测试任何协议的维基

http://testanything.org

它包含 TAP::Parser 食谱

http://testanything.org/testing-with-tap/perl/tap::parser-cookbook.html

方法

类方法

new

my $parser = TAP::Parser->new(\%args);

返回一个新的 TAP::Parser 对象。

参数应为一个哈希引用,其中包含以下键之一

以下键是可选的。

实例方法

next

my $parser = TAP::Parser->new( { source => $file } );
while ( my $result = $parser->next ) {
    print $result->as_string, "\n";
}

此方法一次返回一个解析结果。请注意,它是破坏性的。您无法回溯并检查以前的结果。

如果使用回调,它们将在此调用返回之前发出。

返回的每个结果都是 TAP::Parser::Result 的子类。有关如何使用它们的更多信息,请参阅该模块和相关类。

run

$parser->run;

此方法仅运行解析器并解析所有 TAP。

make_grammar

创建一个新的 TAP::Parser::Grammar 对象并返回它。传递给定的任何参数。

grammar_class 可以自定义,如 "new" 中所述。

make_result

使用解析器的 TAP::Parser::ResultFactory 创建一个新的 TAP::Parser::Result 对象,并返回它。传递给定的任何参数。

result_factory_class 可以自定义,如 "new" 中所述。

make_iterator_factory

3.18 版本新增.

创建一个新的 TAP::Parser::IteratorFactory 对象并返回它。传递给定的任何参数。

iterator_factory_class 可以自定义,如 "new" 中所述。

单个结果

如果您已经阅读了文档中的这一部分,您已经看到了这一点

while ( my $result = $parser->next ) {
    print $result->as_string;
}

返回的每个结果都是 TAP::Parser::Result 子类,称为结果类型

结果类型

基本上,您从 TAP 中获取单个结果。六种类型及其示例如下

每个获取的结果都是不同类型的结果对象。每个结果对象都有通用方法,不同类型可能具有特定于其类型的独特方法。有时,子类可能会覆盖类型方法,但其使用保证是相同的。

通用类型方法

type

返回结果类型,例如 commenttest

as_string

打印令牌的字符串表示形式。但这可能不是确切的输出。测试将添加测试编号(如果不存在),TODO 和 SKIP 指令将大写,并且通常会进行清理。如果您需要令牌的原始文本,请参阅 raw 方法。

raw

返回解析的原始文本行。

is_plan

指示这是否是测试计划行。

is_test

指示这是否是测试行。

is_comment

指示这是否是注释。注释通常仅在将 STDERR 合并到 STDOUT 时才会出现在 TAP 流中。请参阅 merge 选项。

is_bailout

指示这是否是中止行。

is_yaml

指示当前项目是否是 YAML 块。

is_unknown

指示当前行是否可以解析。

is_ok

if ( $result->is_ok ) { ... }

报告给定结果是否已通过。任何不是测试结果的内容都将返回 true。这仅仅是作为一种方便的快捷方式提供,允许您执行以下操作

my $parser = TAP::Parser->new( { source => $source } );
while ( my $result = $parser->next ) {
    # only print failing results
    print $result->as_string unless $result->is_ok;
}

plan 方法

if ( $result->is_plan ) { ... }

如果上述内容评估为 true,则以下方法将在 $result 对象上可用。

plan

if ( $result->is_plan ) {
   print $result->plan;
}

这仅仅是 as_string 的同义词。

directive

my $directive = $result->directive;

如果计划中包含 SKIP 指令,则此方法将返回它。

1..0 # SKIP: why bother?

explanation

my $explanation = $result->explanation;

如果计划中包含 SKIP 指令,则此方法将返回解释(如果有)。

pragma 方法

if ( $result->is_pragma ) { ... }

如果上述内容评估为 true,则以下方法将在 $result 对象上可用。

pragmas

返回一个 pragma 列表,每个 pragma 都是一个 + 或 - 后跟 pragma 名称。

comment 方法

if ( $result->is_comment ) { ... }

如果上述内容评估为 true,则以下方法将在 $result 对象上可用。

comment

if ( $result->is_comment ) {
    my $comment = $result->comment;
    print "I have something to say:  $comment";
}

bailout 方法

if ( $result->is_bailout ) { ... }

如果上述内容评估为 true,则以下方法将在 $result 对象上可用。

explanation

if ( $result->is_bailout ) {
    my $explanation = $result->explanation;
    print "We bailed out because ($explanation)";
}

如果且仅当一个标记是 bailout 标记时,您可以通过此方法获取“解释”。解释是 tap 输出中神秘的“Bail out!”字词之后的文本。

unknown 方法

if ( $result->is_unknown ) { ... }

未知结果没有独特的方法。

test 方法

if ( $result->is_test ) { ... }

如果上述内容评估为 true,则以下方法将在 $result 对象上可用。

ok

my $ok = $result->ok;

返回 oknot ok 状态的文字文本。

number

my $test_number = $result->number;

返回测试的编号,即使原始 TAP 输出没有提供该编号。

description

my $description = $result->description;

返回测试的描述(如果有)。这是测试编号之后但指令之前的部分。

directive

my $directive = $result->directive;

如果测试行中存在任何指令,则返回 TODOSKIP

explanation

my $explanation = $result->explanation;

如果测试具有 TODOSKIP 指令,则此方法将返回随附的解释(如果有)。

not ok 17 - 'Pigs can fly' # TODO not enough acid

对于上面的行,解释是 not enough acid

is_ok

if ( $result->is_ok ) { ... }

返回一个布尔值,指示测试是否通过。请记住,对于 TODO 测试,测试始终通过。

注意:这以前是 passed。后一种方法已弃用,并将发出警告。

is_actual_ok

if ( $result->is_actual_ok ) { ... }

返回一个布尔值,指示测试是否通过,无论其 TODO 状态如何。

注意:这以前是 actual_passed。后一种方法已弃用,并将发出警告。

is_unplanned

if ( $test->is_unplanned ) { ... }

如果测试编号大于计划测试的编号,则此方法将返回 true。未计划的测试将始终is_ok 返回 false,无论测试是否 has_todo(有关此的更多信息,请参阅 TAP::Parser::Result::Test)。

has_skip

if ( $result->has_skip ) { ... }

返回一个布尔值,指示此测试是否具有 SKIP 指令。

has_todo

if ( $result->has_todo ) { ... }

返回一个布尔值,指示此测试是否具有 TODO 指令。

请注意,TODO 测试始终通过。如果您需要知道它们是否真的通过,请检查 is_actual_ok 方法。

in_todo

if ( $parser->in_todo ) { ... }

当最近的结果为 TODO 时为真。在返回 TODO 结果之前变为真,并在返回下一个非 TODO 测试之前一直保持为真。

总结果

解析 TAP 后,您可以使用多种方法深入了解结果并确定对您有意义的内容。

单个结果

这些结果指的是运行的单个测试。

passed

my @passed = $parser->passed; # the test numbers which passed
my $passed = $parser->passed; # the number of tests which passed

此方法让您知道哪些(或多少)测试通过。如果测试失败但有 TODO 指令,则将计为通过测试。

failed

my @failed = $parser->failed; # the test numbers which failed
my $failed = $parser->failed; # the number of tests which failed

此方法让您知道哪些(或多少)测试失败。如果测试通过但有 TODO 指令,则 **不会** 计为失败测试。

actual_passed

# the test numbers which actually passed
my @actual_passed = $parser->actual_passed;

# the number of tests which actually passed
my $actual_passed = $parser->actual_passed;

此方法让您知道哪些(或多少)测试实际通过,无论是否找到 TODO 指令。

actual_ok

此方法是 actual_passed 的同义词。

actual_failed

# the test numbers which actually failed
my @actual_failed = $parser->actual_failed;

# the number of tests which actually failed
my $actual_failed = $parser->actual_failed;

此方法让您知道哪些(或多少)测试实际失败,无论是否找到 TODO 指令。

todo

my @todo = $parser->todo; # the test numbers with todo directives
my $todo = $parser->todo; # the number of tests with todo directives

此方法让您知道哪些(或多少)测试有 TODO 指令。

todo_passed

# the test numbers which unexpectedly succeeded
my @todo_passed = $parser->todo_passed;

# the number of tests which unexpectedly succeeded
my $todo_passed = $parser->todo_passed;

此方法让您知道哪些(或多少)测试实际通过,但被声明为“TODO”测试。

todo_failed

# deprecated in favor of 'todo_passed'.  This method was horribly misnamed.

这是一个命名错误的方法。它指示哪些 TODO 测试意外成功。现在将发出警告并调用 todo_passed

skipped

my @skipped = $parser->skipped; # the test numbers with SKIP directives
my $skipped = $parser->skipped; # the number of tests with SKIP directives

此方法让您知道哪些(或多少)测试有 SKIP 指令。

Pragma

pragma

获取或设置 pragma。要获取 pragma 的状态

if ( $p->pragma('strict') ) {
    # be strict
}

要设置 pragma 的状态

$p->pragma('strict', 1); # enable strict mode

pragmas

获取当前启用的所有 pragma 的列表

my @pragmas_enabled = $p->pragmas;

摘要结果

这些结果是关于单个测试程序总结果的“元”信息。

plan

my $plan = $parser->plan;

如果找到,则返回测试计划。

good_plan

已弃用。请使用 is_good_plan 代替。

is_good_plan

if ( $parser->is_good_plan ) { ... }

返回一个布尔值,指示计划的测试数量是否与实际运行的测试数量匹配。

注意: 此方法以前称为 good_plan。 后者已弃用,将发出警告。

既然我们谈到这个话题...

tests_planned

print $parser->tests_planned;

返回根据计划计划的测试数量。 例如,计划为“1..17”意味着计划了 17 个测试。

tests_run

print $parser->tests_run;

返回实际运行的测试数量。 希望这将与 $parser->tests_planned 的数量匹配。

skip_all

如果所有测试都被跳过,则返回一个真值(实际上是跳过的原因)。

start_time

返回创建解析器时的挂钟时间。

end_time

返回看到 TAP 输入结束时的挂钟时间。

start_times

返回创建解析器时的 CPU 时间(如 "perlfunc 中的 times")。

end_times

返回看到 TAP 输入结束时的 CPU 时间(如 "perlfunc 中的 times")。

has_problems

if ( $parser->has_problems ) {
    ...
}

这是一个“万能”方法,如果任何测试当前失败,任何 TODO 测试意外成功或出现任何解析错误,则返回 true。

version

$parser->version;

解析器完成后,这将返回解析的 TAP 的版本号。 版本号是在 TAP 版本 13 中引入的,因此如果找不到版本号,则假定为版本 12。

exit

$parser->exit;

解析器完成后,这将返回退出状态。 如果解析器运行了可执行文件,则返回可执行文件的退出状态。

wait

$parser->wait;

解析器完成后,这将返回等待状态。 如果解析器运行了可执行文件,则返回可执行文件的等待状态。 否则,这仅返回 exit 状态。

ignore_exit

$parser->ignore_exit(1);

告诉解析器在确定测试是否通过时忽略测试的退出状态。通常,退出状态非零的测试被认为是失败的,即使所有单独的测试都通过了。在无法控制测试脚本的退出值的情况下,使用此选项来忽略它。

parse_errors

my @errors = $parser->parse_errors; # the parser errors
my $errors = $parser->parse_errors; # the number of parser_errors

幸运的是,所有 TAP 输出都是完美的。如果它不是,此方法将返回解析器错误。请注意,解析器无法识别的垃圾行不是错误。这允许此解析器处理 TAP 的未来版本。以下是解析器报告的所有 TAP 错误

get_select_handles

获取可以传递给select的文件句柄列表,以确定此解析器的就绪状态。

delete_spool

删除并返回卷轴。

my $fh = $parser->delete_spool;

回调

如前所述,可以在TAP::Parser构造函数中添加一个“回调”键。如果存在,如果使用run方法,则将调用与给定结果类型相对应的每个回调,并将结果作为参数。回调应为子例程引用(或匿名子例程),它以解析器结果作为参数调用。

my %callbacks = (
    test    => \&test_callback,
    plan    => \&plan_callback,
    comment => \&comment_callback,
    bailout => \&bailout_callback,
    unknown => \&unknown_callback,
);

my $aggregator = TAP::Parser::Aggregator->new;
for my $file ( @test_files ) {
    my $parser = TAP::Parser->new(
        {
            source    => $file,
            callbacks => \%callbacks,
        }
    );
    $parser->run;
    $aggregator->add( $file, $parser );
}

回调也可以这样添加

$parser->callback( test => \&test_callback );
$parser->callback( plan => \&plan_callback );

以下键允许回调。这些键区分大小写。

TAP 语法

如果您正在寻找 EBNF 语法,请参阅 TAP::Parser::Grammar

向后兼容性

Perl-QA 列表试图确保与 Test::Harness 的向后兼容性。但是,有一些细微的差异。

差异

子类化

如果您发现需要提供自定义功能(就像使用 Test::Harness::Straps 一样),那么您很幸运:TAP::Parser 及其朋友旨在易于插入和/或子类化。

在您开始之前,了解一些事情很重要

  1. 所有 TAP::* 对象都继承自 TAP::Object

  2. 许多 TAP::* 类都有一个子类化部分来指导您。

  3. 请注意,TAP::Parser 被设计为中央“制造商” - 也就是说:它负责创建 TAP::Parser::* 命名空间中的大多数新对象。

    这使得您可以拥有一个配置应该使用哪些子类的单一位置,这意味着在许多情况下,您会发现您只需要对解析器的组件之一进行子类化。

    此规则的例外是SourceHandlersIterators,但它们都是使用可自定义的IteratorFactory创建的。

  4. 通过子类化,您最终可能会覆盖未记录的方法。这本身并不是一件坏事,但请注意,未记录的方法可能会在不同版本之间发生更改而不会发出警告 - 我们无法保证向后兼容性。如果任何已记录的方法需要更改,它将首先被弃用,并在以后的版本中更改。

解析器组件

来源

TAP 解析器从单个原始来源的 TAP 中获取输入,该来源可以来自任何地方(文件、可执行文件、数据库、IO 处理程序、URI 等)。该来源被捆绑在一个TAP::Parser::Source对象中,该对象收集有关它的元数据。然后,解析器使用TAP::Parser::IteratorFactory来确定使用哪个TAP::Parser::SourceHandler通过"迭代器"将原始来源转换为 TAP 流。

如果您只是想让TAP::Parser处理新的 TAP 来源,您可能不需要对TAP::Parser本身进行子类化。相反,您需要创建一个新的TAP::Parser::SourceHandler类,并将其插入解析器,使用sources参数传递给"new"。在您开始编写一个之前,请阅读TAP::Parser::IteratorFactory以了解该系统的工作原理。

如果您发现您确实需要使用自己的迭代器工厂,您仍然可以通过设置"iterator_factory_class"来做到这一点,而无需对TAP::Parser进行子类化。

如果您只需要在创建时自定义对象,请对TAP::Parser进行子类化并覆盖"make_iterator_factory"

请注意,make_sourcemake_perl_source已被弃用,现在已删除。

迭代器

TAP 解析器使用迭代器来循环遍历从其给定的读取的 TAP 。默认情况下,有几种类型的迭代器可用,它们都是TAP::Parser::Iterator的子类。选择使用哪个迭代器是迭代器工厂的责任,尽管它只是委托给它使用的源处理程序

如果您正在编写自己的TAP::Parser::SourceHandler,您可能也需要创建自己的迭代器。如果是这样,您需要子类化TAP::Parser::Iterator

请注意,"make_iterator"弃用,现已删除。

结果

TAP 解析器在遍历输入时创建TAP::Parser::Result。有相当多的结果类型可用;选择使用哪个类是结果工厂的责任。

要创建您自己的结果类型,您有两个选择

选项 1

子类化TAP::Parser::Result,并将您的新结果类型/类注册到默认的TAP::Parser::ResultFactory

选项 2

子类化TAP::Parser::ResultFactory 本身,并实现您自己的TAP::Parser::Result 创建逻辑。然后,您需要通过设置result_factory_class参数来定制解析器使用的类。有关更多详细信息,请参见"new"

如果您需要在创建时定制对象,请子类化TAP::Parser 并覆盖"make_result"

语法

TAP::Parser::Grammar 是解析器的核心。它对 TAP 输入进行标记化,并生成结果。如果您需要定制其行为,您可能应该首先熟悉源代码。讲座就到这里。

子类化TAP::Parser::Grammar,并通过设置grammar_class参数来定制您的解析器。有关更多详细信息,请参见"new"

如果您需要在创建时定制对象,请子类化TAP::Parser 并覆盖"make_grammar"

致谢

以下所有人员都提供了帮助。错误报告、补丁、(不)道德支持或仅仅是鼓励的话语都已出现。

作者

Curtis "Ovid" Poe <[email protected]>

Andy Armstong <[email protected]>

Eric Wilhelm @ <ewilhelm at cpan dot org>

Michael Peters <mpeters at plusthree dot com>

Leif Eriksen <leif dot eriksen at bigpond dot com>

Steve Purkis <[email protected]>

Nicholas Clark <[email protected]>

Lee Johnson <notfadeaway at btinternet dot com>

Philippe Bruhat <[email protected]>

错误

请将任何错误或功能请求报告给[email protected],或通过网页界面在http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Test-Harness报告。我们会收到通知,然后您会在我们进行更改时自动收到有关您错误的进度通知。

显然,包含补丁的错误是最好的。如果您愿意,您可以通过匿名签出最新版本来针对 bleed 进行修补

git clone git://github.com/Perl-Toolchain-Gang/Test-Harness.git

版权 & 许可

版权所有 2006-2008 Curtis "Ovid" Poe,保留所有权利。

本程序是自由软件;您可以在 Perl 本身相同的条款下重新发布和/或修改它。