Test::Alien(3)

πŸ’– Test::Alien β€” the manual page, but make it cute πŸ’–

okay bestie, so this is Test::Alien from the perl user-contributed docs. it's version 2.88 and it's literally the testing toolbox for Alien modules. no cap. let's get into it 🫢


✨ NAME ✨

Test::Alien β€” testing tools for Alien modules. that's it, that's the whole name. iconic.


🌸 VERSION 🌸

version 2.88. she's current, she's thriving πŸ’…


πŸŽ€ SYNOPSIS πŸŽ€

okay so three whole vibes here. buckle up.

testing the commands that come with your Alien:

use Test2::V0;
use Test::Alien;
use Alien::patch;

alien_ok 'Alien::patch';
run_ok([ 'patch', '--version' ])
  ->success
  # we only accept the version written
  # by Larry ...
  ->out_like(qr{Larry Wall});

done_testing;

testing that your library works with XS:

use Test2::V0;
use Test::Alien;
use Alien::Editline;

alien_ok 'Alien::Editline';
my $xs = do { local $/; <DATA> };
xs_ok $xs, with_subtest {
  my($module) = @_;
  ok $module->version;
};

done_testing;

__DATA__

#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include <editline/readline.h>

const char *
version(const char *class)
{
  return rl_library_version;
}

MODULE = TA_MODULE PACKAGE = TA_MODULE

const char *version(class);
    const char *class;

testing that your library works with FFI::Platypus:

use Test2::V0;
use Test::Alien;
use Alien::LibYAML;

alien_ok 'Alien::LibYAML';
ffi_ok { symbols => ['yaml_get_version'] }, with_subtest {
  my($ffi) = @_;
  my $get_version = $ffi->function(yaml_get_version => ['int*','int*','int*'] => 'void');
  $get_version->call(\my $major, \my $minor, \my $patch);
  like $major, qr{[0-9]+};
  like $minor, qr{[0-9]+};
  like $patch, qr{[0-9]+};
};

done_testing;

πŸ¦‹ DESCRIPTION πŸ¦‹

so this module hands you the tools to test Alien modules. it's got hooks so it plays nice with Alien::Base based modules, but you can also use the synthetic interface to test Alien modules that are not Alien::Base based. and the prerequisites? very modest. lowkey humble of it. πŸŽ€

before this module existed, the best way to test an Alien module was via Test::CChecker. the main downside of that one is that it's heavily influenced by β€” and uses β€” ExtUtils::CChecker, which is a tool for checking stuff about your compiler at install time. it was also written back before Alien::Base got as stable as it is today. in particular, Test::CChecker does its testing by creating an executable and running it. but unfortunately Perl uses extensions by creating dynamic libraries and linking them into the Perl process, which is different in subtle and error prone ways 😭. this module tries to test the libraries the way they'll actually be used, via either XS or FFI::Platypus. it also gives you a mechanism for testing binaries that the various Alien modules provide (like Alien::gmake and Alien::patch, for example).

and here's the slay part: Alien modules can actually be usable without a compiler, or without FFI::Platypus (say the library comes from the system and you're using FFI::Platypus, or you're building from source and you're using XS), so tests with missing prerequisites get automatically skipped. for example, xs_ok will automatically skip itself if a compiler isn't found, and ffi_ok will automatically skip itself if FFI::Platypus isn't installed. considerate queen behavior fr fr πŸ‘‘


πŸ’… FUNCTIONS πŸ’…

🌈 alien_ok

alien_ok $alien, $message;
alien_ok $alien;

loads the given Alien instance or class. checks that the instance or class conforms to the same interface as Alien::Base. it'll be used by subsequent tests. the $alien module only needs to provide these methods to conform to the Alien::Base interface:

  • cflags β€” a string containing the compiler flags.
  • libs β€” a string containing the linker and library flags.
  • dynamic_libs β€” a list of dynamic libraries. returns an empty list if the Alien module doesn't provide this.
  • bin_dir β€” the directory containing tool binaries. returns an empty list if the Alien module doesn't provide this.

if your Alien module doesn't conform to this interface, then you can create a synthetic Alien module using the synthetic function. problem solved bestie πŸ’–

🧚 synthetic

my $alien = synthetic \%config;

creates a synthetic Alien module which you can pass into alien_ok. \%config can contain these keys (and all of them are optional, so no pressure):

  • cflags β€” a string containing the compiler flags.
  • cflags_static β€” a string containing the static compiler flags (optional).
  • libs β€” a string containing the linker and library flags.
  • libs_static β€” a string containing the static linker flags (optional).
  • dynamic_libs β€” a list reference containing the dynamic libraries.
  • bin_dir β€” tool binary directory.
  • runtime_prop β€” runtime properties.

see Test::Alien::Synthetic for more deets ✨

🌸 run_ok

my $run = run_ok $command;
my $run = run_ok $command, $message;

runs the given command, falling back on any Alien::Base#bin_dir methods provided by the Alien modules you specified with alien_ok.

$command can be either a string or an array reference.

okay so it only fails if the command cannot be found, or if it's killed by a signal! that's the whole list. that's it.

returns a Test::Alien::Run object, which you can use to test the exit status, output and standard error.

and it always returns an instance of Test::Alien::Run, even if the command couldn't be found. consistent queen πŸ‘‘

πŸ’œ xs_ok

xs_ok $xs;
xs_ok $xs, $message;

compiles, links the given XS code, and attaches it to Perl. the whole glow-up ✨

if you use the special module name TA_MODULE in your XS code, it'll be replaced by an automatically generated package name. this is handy if you wanna pass the same XS code to multiple calls to xs_ok without the later calls replacing the earlier ones. iykyk.

$xs can be either a string containing the XS code, or a hash reference with these keys:

  • xs β€” the XS code. this is the only required element.
  • pxs β€” extra ExtUtils::ParseXS arguments passed in as a hash reference.
  • cbuilder_check β€” the compile check that should be done prior to attempting to build. should be one of have_compiler or have_cplusplus. defaults to have_compiler.
  • cbuilder_config β€” hash to override values normally provided by Config.
  • cbuilder_compile β€” extra The ExtUtils::CBuilder arguments passed in as a hash reference.
  • cbuilder_link β€” extra The ExtUtils::CBuilder arguments passed in as a hash reference.
  • verbose β€” spew copious debug information via test note.

you can use the with_subtest keyword to conditionally run a subtest if the xs_ok call succeeds. if xs_ok doesn't work, then the subtest gets automatically skipped. like so:

xs_ok $xs, with_subtest {
  # skipped if $xs fails for some reason
  my($module) = @_;
  is $module->foo, 1;
};

the module name detected during the XS parsing phase gets passed into the subtest. super helpful when you're using a generated module name 🫢

if you need to test XS C++ interfaces, see Test::Alien::CPP.

caveats: xs_ok uses ExtUtils::ParseXS, which may call exit under certain error conditions. while that's not really a good thing to happen in the middle of a test, it usually indicates a real failure condition, and it should return a failure condition, so the test should still fail overall. πŸ’€

[version 2.53]

as of version 2.53, xs_ok will only remove temporary generated files if the test is successful by default. you can force either always or never removing the temporary generated files using the TEST_ALIEN_ALWAYS_KEEP environment variable (peep "ENVIRONMENT" below πŸ‘€).

πŸ“ ffi_ok

ffi_ok;
ffi_ok \%opt;
ffi_ok \%opt, $message;

tests that FFI::Platypus works.

\%opt is a hash reference with these keys (all optional, live your life):

  • symbols β€” list references of symbols that must be found for the test to succeed.
  • ignore_not_found β€” ignores symbols that aren't found. this affects functions accessed via FFI::Platypus#attach and FFI::Platypus#function methods, and does not influence the symbols key above.
  • lang β€” set the language. used primarily for language specific native types.
  • api β€” set the API. api = 1 requires FFI::Platypus 0.99 or later. this option was added with Test::Alien version 1.90, so your use line should include this version as a safeguard to make sure it works:
use Test::Alien 1.90;
...
ffi_ok ...;

same as with xs_ok above, you can use the with_subtest keyword to specify a subtest to be run if ffi_ok succeeds (it'll skip otherwise). the FFI::Platypus instance gets passed into the subtest as the first argument. for example:

ffi_ok with_subtest {
  my($ffi) = @_;
  is $ffi->function(foo => [] => 'void')->call, 42;
};

🌈 helper_ok

helper_ok $name;
helper_ok $name, $message;

tests that the given helper has been defined. short and sweet ✨

πŸ‘‘ plugin_ok

[version 2.52]

plugin_ok $plugin_name, $message;
plugin_ok [$plugin_name, @args], $message;

this applies an Alien::Build::Plugin to the interpolator used by helper_ok, interpolate_template_is and interpolate_run_ok, so you can test with any helpers that plugin provides. useful, for example, for getting %{configure} from Alien::Build::Plugin::Build::Autoconf. chef's kiss πŸ’…

🧚 interpolate_template_is

interpolate_template_is $template, $string;
interpolate_template_is $template, $string, $message;
interpolate_template_is $template, $regex;
interpolate_template_is $template, $regex, $message;

tests that the given template, when evaluated with the appropriate helpers, will match either the given string or regular expression. πŸ’–

⭐ interpolate_run_ok

[version 2.52]

my $run = interpolate_run_ok $command;
my $run = interpolate_run_ok $command, $message;

this is the same as run_ok, except it runs the command through the interpolator first. tiny lil upgrade, big lil difference 😌


πŸ”₯ ENVIRONMENT πŸ”₯

  • TEST_ALIEN_ALWAYS_KEEP β€” if this is defined then it'll override the built in logic that decides if the temporary files generated by xs_ok should be kept when the test file terminates. if set to true, the generated files will always be kept. if set to false, then they'll always be removed.
  • TEST_ALIEN_ALIENS_MISSING β€” by default, this module will warn you if some tools are used without first invoking alien_ok. this is usually a mistake, but if you really do wanna use one of these tools with no aliens loaded, you can set this environment variable to false. (living dangerously, we respect it πŸ™ˆ)

🌈 SEE ALSO 🌈

  • Alien
  • Alien::Base
  • Alien::Build
  • alienfile
  • Test2
  • Test::Alien::Run
  • Test::Alien::CanCompile
  • Test::Alien::CanPlatypus
  • Test::Alien::Synthetic
  • Test::Alien::CPP

more of this page coming in part 2, don't go anywhere bestie 🫢✨

πŸ‘‘ AUTHOR πŸ‘‘

Okay so this whole thing was brought to you by:

  • Author: Graham Ollis <plicease@cpan.org>

And bestie, the contributor list is stacked. Like, genuinely iconic roster energy:

  • Diab Jerius (DJERIUS)
  • Roy Storey (KIWIROY)
  • Ilya Pavlov
  • David Mertens (run4flat)
  • Mark Nunberg (mordy, mnunberg)
  • Christian Walde (Mithaldu)
  • Brian Wightman (MidLifeXis)
  • Zaki Mughal (zmughal)
  • mohawk (mohawk2, ETJ)
  • Vikas N Kumar (vikasnkumar)
  • Flavio Poletti (polettix)
  • Salvador FandiΓ±o (salva)
  • Gianni Ceccarelli (dakkar)
  • Pavel Shaydo (zwon, trinitum)
  • Kang-min Liu (εŠ‰εΊ·ζ°‘, gugod)
  • Nicholas Shipp (nshp)
  • Juan JuliΓ‘n Merelo GuervΓ³s (JJ)
  • Joel Berger (JBERGER)
  • Petr PΓ­saΕ™ (ppisar)
  • Lance Wicks (LANCEW)
  • Ahmad Fatoum (a3f, ATHREEF)
  • JosΓ© JoaquΓ­n Atria (JJATRIA)
  • Duke Leto (LETO)
  • Shoichi Kaji (SKAJI)
  • Shawn Laffan (SLAFFAN)
  • Paul Evans (leonerd, PEVANS)
  • HΓ₯kon HΓ¦gland (hakonhagland, HAKONH)
  • nick nauwelaerts (INPHOBIA)
  • Florian Weimer
  • Marcel Telka (mtelka)

Every single one of them, no skips, we appreciate all of y'all fr fr πŸ’œ


This software is copyright (c) 2011-2022 by Graham Ollis.

It's free software β€” you can redistribute it and/or modify it under the exact same terms as the Perl 5 programming language system itself. So basically, same vibe as Perl 5, same rules, go wild (respectfully). πŸŽ€


And that's a wrap on Test::Alien(3), bestie!! πŸ¦‹ This page ships as part of perl v5.42.3, dated 2026-09-21 β€” that's the version-and-date energy we're closing on. Go test your Alien stuff, slay, and remember: every option, every default, every single contributor name stayed exactly where it belongs. πŸ’…βœ¨

πŸ“¦ where this page comes from