App-diff_spreadsheets
view release on metacpan or search on metacpan
t/t_TestCommon.pm view on Meta::CPAN
# License: Public Domain or CC0
# See https://creativecommons.org/publicdomain/zero/1.0/
# The author, Jim Avera (jim.avera at gmail) has waived all copyright and
# related or neighboring rights to the content of this file.
# Attribution is requested but is not required.
#
# PLEASE NOTE that the above applies to THIS FILE ONLY. Other files in the
# same distribution or in other collections may have more restrictive terms.
# NO use strict; use warnings here to avoid conflict with t_Common which sets them
# t_TestCommon -- setup and tools specifically for tests.
#
# This file is intended to be identical in all my module distributions.
#
# Loads Test2::V0 (except with ":no-Test2"), which sets UTF-8 enc/dec
# for test-harness streams (but *not* STD* or new filehandles).
#
# Makes STDIN, STDOUT & STDERR UTF-8 auto de/encode
#
# Imports 'utf8' so scripts can be written in UTF-8 encoding
#
# warnings are *not* imported, to avoid clobbering 'no warnings ...'
# settings done beforehand (e.g. via t_Common).
#
# If @ARGV contains -d etc. those options are removed from @ARGV
# and the corresponding globals are set: $debug, $verbose, $silent
# (the globals are not exported by default). In addition, the
# hash %dvs is initialized with those values.
#
# ':silent' captures stdout & stderr and dies at exit if anything was
# written (Test::More output and output via 'note'/'diag' excepted).
# Note: Currently incompatible with Capture::Tiny !
#
# Exports various utilites & wrappers for ok() and like()
#
# Everything not specifically test-related is in the separate
# module t_Common (which is not necessairly just for tests).
package t_TestCommon;
use t_Common qw/oops mytempfile mytempdir/; # also List::Util etc.
use v5.16; # must have PerlIO for in-memory files for ':silent';
use Carp;
BEGIN{
confess "Test::More already loaded!" if defined( &Test::More::ok );
confess "Test2::V0 already loaded!" if defined( &Test2::V0::import );
# Force UTF-8 (and remove any other encoder) regardless of the
# environment/terminal. This allows tests to use capture {...} and check
# the results independent of the environment, even though printed results
# may be garbled.
binmode(STDIN, ":raw:encoding(UTF-8):crlf");
if ($^O eq "MSWin32") {
binmode(STDOUT, ":raw:encoding(UTF-8)");
binmode(STDERR, ":raw:encoding(UTF-8)");
} else {
binmode(STDOUT, ":raw:crlf:encoding(UTF-8)");
binmode(STDERR, ":raw:crlf:encoding(UTF-8)");
}
# Disable buffering
STDERR->autoflush(1);
STDOUT->autoflush(1);
# NO! Momentarily I thought it would be a Good Thing to set a standard
# terminal width in COLUMNS ignoring the actual terminal. But some
# modules test term width autodetect by unsetting COLUMNS and would
# then get a (possibly) different result.
#
# So it is necessary for *every* package which probes for terminal width
# use robust code which won't fail even if there is no terminal
# (which is gross -- see Data::Dumper::Interp::_get_terminal_width)
##$ENV{COLUMNS} = 80;
}
use POSIX ();
use utf8;
use JSON ();
require Exporter;
use parent 'Exporter';
our @EXPORT = qw/silent
bug
t_ok t_is t_like
ok_with_lineno is_with_lineno like_with_lineno
rawstr showstr showcontrols displaystr
show_white show_empty_string
fmt_codestring
verif_no_internals_mentioned
insert_loc_in_evalstr verif_eval_err
tdir
timed_run
mycheckeq_literal expect1 mycheck _mycheck_end
arrays_eq hash_subset
run_perlscript
@quotes
string_to_tempfile
tmpcopy_if_writeable
my_capture my_capture_merged my_tee_merged
/;
our @EXPORT_OK = qw/$savepath $debug $silent $verbose %dvs dprint dprintf/;
use Import::Into;
use Data::Dumper;
use Cwd qw/getcwd abs_path/;
use POSIX qw/INT_MAX/;
use File::Basename qw/dirname/;
use Capture::Tiny qw/capture capture_merged tee_merged/;
use Env qw/@PATH @PERL5LIB/; # ties @PATH, @PERL5LIB
use Config;
BEGIN {
unless (Cwd::abs_path(__FILE__) =~ /Data-Dumper-Interp/) {
# Unless we are testing DDI
#$Data::Dumper::Interp::Foldwidth = undef; # use terminal width
$Data::Dumper::Interp::Useqq = "controlpics:unicode";
}
}
t/t_TestCommon.pm view on Meta::CPAN
#--------------- :silent support ---------------------------
# N.B. It appears, experimentally, that output from ok(), like() and friends
# is not written to the test process's STDOUT or STDERR, so we do not need
# to worry about ignoring those normal outputs (somehow everything is
# merged at the right spots, presumably by a supervisory process).
# [Note May23: This was with Test::More may *NOT* be true with Test2::V0 !!]
#
# Therefore tests can be simply wrapped in silent{...} or the entire
# program via the ':silent' tag; however any "Silence expected..." diagnostics
# will appear at the end, perhaps long after the specific test case which
# emitted the undesired output.
my ($orig_stdOUT, $orig_stdERR, $orig_DIE_trap);
my ($inmem_stdOUT, $inmem_stdERR) = ("", "");
my $silent_mode;
use Encode qw/decode FB_WARN FB_PERLQQ FB_CROAK LEAVE_SRC/;
my $start_silent_loc = "";
sub _finish_silent() {
confess "not in silent mode" unless $silent_mode;
close STDERR;
open(STDERR, ">>&", $orig_stdERR) or exit(198);
close STDOUT;
open(STDOUT, ">>&", $orig_stdOUT) or die "orig_stdOUT: $!";
$SIG{__DIE__} = $orig_DIE_trap;
$silent_mode = 0;
# The in-memory files hold octets; decode them before printing
# them out (when they will be re-encoded for the user's terminal).
my $errmsg;
if ($inmem_stdOUT ne "") {
print STDOUT "--- saved STDOUT ---\n";
print STDOUT decode("utf8", $inmem_stdOUT, FB_PERLQQ|LEAVE_SRC);
$errmsg //= "Silence expected on STDOUT";
}
if ($inmem_stdERR ne "") {
print STDERR "--- saved STDERR ---\n";
print STDERR decode("utf8", $inmem_stdERR, FB_PERLQQ|LEAVE_SRC);
$errmsg = $errmsg ? "$errmsg and STDERR" : "Silence expected on STDERR";
}
defined($errmsg) ? $errmsg." at $start_silent_loc\n" : undef;
}
sub _start_silent() {
confess "nested silent treatments not supported" if $silent_mode;
$silent_mode = 1;
for (my $N=0; ;++$N) {
my ($pkg, $file, $line) = caller($N);
$start_silent_loc = "$file line $line", last if $pkg ne __PACKAGE__;
}
$orig_DIE_trap = $SIG{__DIE__};
$SIG{__DIE__} = sub{
return if $^S or !defined($^S); # executing an eval, or Perl compiler
my @diemsg = @_;
my $err=_finish_silent(); warn $err if $err;
die @diemsg;
};
my @OUT_layers = grep{ $_ ne "unix" } PerlIO::get_layers(*STDOUT, output=>1);
open($orig_stdOUT, ">&", \*STDOUT) or die "dup STDOUT: $!";
close STDOUT;
open(STDOUT, ">", \$inmem_stdOUT) or die "redir STDOUT: $!";
binmode(STDOUT); binmode(STDOUT, ":utf8");
my @ERR_layers = grep{ $_ ne "unix" } PerlIO::get_layers(*STDERR, output=>1);
open($orig_stdERR, ">&", \*STDERR) or die "dup STDERR: $!";
close STDERR;
open(STDERR, ">", \$inmem_stdERR) or die "redir STDERR: $!";
binmode(STDERR); binmode(STDERR, ":utf8");
}
sub silent(&) {
my $wantarray = wantarray;
my $code = shift;
_start_silent();
my @result = do{
if (defined $wantarray) {
return( $wantarray ? $code->() : scalar($code->()) );
}
$code->();
my $dummy_result; # so previous call has null context
};
my $errmsg = _finish_silent();
local $Test::Builder::Level = $Test::Builder::Level + 1;
Test2::V0::ok(! defined($errmsg), $errmsg);
wantarray ? @result : $result[0]
}
END{
if ($silent_mode) {
my $errmsg = _finish_silent();
if ($errmsg) {
#die $errmsg; # it's too late to call ok(false)
warn $errmsg;
exit 199; # recognizable exit code in case message is lost
}
}
}
#--------------- (end of :silent stuff) ---------------------------
# Find the ancestor build or checkout directory (it contains a "lib" subdir)
# and derive the package name from e.g. "My-Pack" or "My-Pack-1.234"
# If we are not part of a CPAN distribution tree, then silently continue
# but croak if verif_no_internals_mentioned() is later used.
my $testee_top_module;
for (my $path=path(__FILE__);
$path ne Path::Tiny->rootdir; $path=$path->parent) {
if (-e (my $p = $path->child("dist.ini"))) {
$p->slurp_utf8() =~ /^ *name *= *(\S+)/im or oops;
($testee_top_module = $1) =~ s/-/::/g;
last
}
if (-e (my $p = $path->child("MYMETA.json"))) {
$testee_top_module = JSON->new->decode($p->slurp_utf8())->{name};
$testee_top_module =~ s/-/::/g;
last;
}
}
sub verif_no_internals_mentioned($) { # croaks if references found
my $original = shift;
oops "This may not be used except in a CPAN distribution tree"
unless $testee_top_module;
return if $Carp::Verbose;
local $_ = $original;
# Ignore glob refs like \*{"..."}
s/(?<!\\)\\\*\{"[^"]*"\}//g;
# Ignore globs like *main::STDOUT or *main::$f
( run in 1.405 second using v1.01-cache-2.11-cpan-df04353d9ac )