1################################################################################
2##
3##  Version 3.x, Copyright (C) 2004-2013, Marcus Holland-Moritz.
4##  Version 2.x, Copyright (C) 2001, Paul Marquess.
5##  Version 1.x, Copyright (C) 1999, Kenneth Albanowski.
6##
7##  This program is free software; you can redistribute it and/or
8##  modify it under the same terms as Perl itself.
9##
10################################################################################
11
12=tests plan => 238
13
14BEGIN {
15  if ($ENV{'SKIP_SLOW_TESTS'}) {
16    for (1 .. 238) {
17      skip("skip: SKIP_SLOW_TESTS", 0);
18    }
19    exit 0;
20  }
21}
22
23use File::Path qw/rmtree mkpath/;
24use Config;
25
26my $tmp = 'ppptmp';
27my $inc = '';
28my $isVMS = $^O eq 'VMS';
29my $isMAC = $^O eq 'MacOS';
30my $perl = find_perl();
31
32rmtree($tmp) if -d $tmp;
33mkpath($tmp) or die "mkpath $tmp: $!\n";
34chdir($tmp) or die "chdir $tmp: $!\n";
35
36if ($ENV{'PERL_CORE'}) {
37  if (-d '../../lib') {
38    if ($isVMS) {
39      $inc = '"-I../../lib"';
40    }
41    elsif ($isMAC) {
42      $inc = '-I:::lib';
43    }
44    else {
45      $inc = '-I../../lib';
46    }
47    unshift @INC, '../../lib';
48  }
49}
50if ($perl =~ m!^\./!) {
51  $perl = ".$perl";
52}
53
54END {
55  chdir('..') if !-d $tmp && -d "../$tmp";
56  rmtree($tmp) if -d $tmp;
57}
58
59ok(&Devel::PPPort::WriteFile("ppport.h"));
60
61# Check GetFileContents()
62ok(-e "ppport.h", 1);
63
64my $data;
65
66open(F, "<ppport.h") or die "Failed to open ppport.h: $!";
67while(<F>) {
68  $data .= $_;
69}
70close(F);
71
72ok(Devel::PPPort::GetFileContents("ppport.h"), $data);
73ok(Devel::PPPort::GetFileContents(), $data);
74
75sub comment
76{
77  my $c = shift;
78  my $x = 0;
79  $c =~ s/^/sprintf("# %2d| ", ++$x)/meg;
80  $c .= "\n" unless $c =~ /[\r\n]$/;
81  print $c;
82}
83
84sub ppport
85{
86  my @args = ('ppport.h', @_);
87  unshift @args, $inc if $inc;
88  my $run = $perl =~ m/\s/ ? qq("$perl") : $perl;
89  $run .= ' -MMac::err=unix' if $isMAC;
90  for (@args) {
91    $_ = qq("$_") if $isVMS && /^[^"]/;
92    $run .= " $_";
93  }
94  print "# *** running $run ***\n";
95  $run .= ' 2>&1' unless $isMAC;
96  my @out = `$run`;
97  my $out = join '', @out;
98  comment($out);
99  return wantarray ? @out : $out;
100}
101
102sub matches
103{
104  my($str, $re, $mod) = @_;
105  my @n;
106  eval "\@n = \$str =~ /$re/g$mod;";
107  if ($@) {
108    my $err = $@;
109    $err =~ s/^/# *** /mg;
110    print "# *** ERROR ***\n$err\n";
111  }
112  return $@ ? -42 : scalar @n;
113}
114
115sub eq_files
116{
117  my($f1, $f2) = @_;
118  return 0 unless -e $f1 && -e $f2;
119  local *F;
120  for ($f1, $f2) {
121    print "# File: $_\n";
122    unless (open F, $_) {
123      print "# couldn't open $_: $!\n";
124      return 0;
125    }
126    $_ = do { local $/; <F> };
127    close F;
128    comment($_);
129  }
130  return $f1 eq $f2;
131}
132
133my @tests;
134
135for (split /\s*={70,}\s*/, do { local $/; <DATA> }) {
136  s/^\s+//; s/\s+$//;
137  my($c, %f);
138  ($c, @f{m/-{20,}\s+(\S+)\s+-{20,}/g}) = split /\s*-{20,}\s+\S+\s+-{20,}\s*/;
139  push @tests, { code => $c, files => \%f };
140}
141
142my $t;
143for $t (@tests) {
144  print "#\n", ('# ', '-'x70, "\n")x3, "#\n";
145  my $f;
146  for $f (keys %{$t->{files}}) {
147    my @f = split /\//, $f;
148    if (@f > 1) {
149      pop @f;
150      my $path = join '/', @f;
151      mkpath($path) or die "mkpath('$path'): $!\n";
152    }
153    my $txt = $t->{files}{$f};
154    local *F;
155    open F, ">$f" or die "open $f: $!\n";
156    print F "$txt\n";
157    close F;
158    print "# *** writing $f ***\n";
159    comment($txt);
160  }
161
162  print "# *** evaluating test code ***\n";
163  comment($t->{code});
164
165  eval $t->{code};
166  if ($@) {
167    my $err = $@;
168    $err =~ s/^/# *** /mg;
169    print "# *** ERROR ***\n$err\n";
170  }
171  ok($@, '');
172
173  for (keys %{$t->{files}}) {
174    unlink $_ or die "unlink('$_'): $!\n";
175  }
176}
177
178sub find_perl
179{
180  my $perl = $^X;
181
182  return $perl if $isVMS;
183
184  my $exe = $Config{'_exe'} || '';
185
186  if ($perl =~ /^perl\Q$exe\E$/i) {
187    $perl = "perl$exe";
188    eval "require File::Spec";
189    if ($@) {
190      $perl = "./$perl";
191    } else {
192      $perl = File::Spec->catfile(File::Spec->curdir(), $perl);
193    }
194  }
195
196  if ($perl !~ /\Q$exe\E$/i) {
197    $perl .= $exe;
198  }
199
200  warn "find_perl: cannot find $perl from $^X" unless -f $perl;
201
202  return $perl;
203}
204
205__DATA__
206
207my $o = ppport(qw(--help));
208ok($o =~ /^Usage:.*ppport\.h/m);
209ok($o =~ /--help/m);
210
211$o = ppport(qw(--version));
212ok($o =~ /^This is.*ppport.*\d+\.\d+(?:_?\d+)?\.$/);
213
214$o = ppport(qw(--nochanges));
215ok($o =~ /^Scanning.*test\.xs/mi);
216ok($o =~ /Analyzing.*test\.xs/mi);
217ok(matches($o, '^Scanning', 'm'), 1);
218ok(matches($o, 'Analyzing', 'm'), 1);
219ok($o =~ /Uses Perl_newSViv instead of newSViv/);
220
221$o = ppport(qw(--quiet --nochanges));
222ok($o =~ /^\s*$/);
223
224---------------------------- test.xs ------------------------------------------
225
226Perl_newSViv();
227
228===============================================================================
229
230# check if C and C++ comments are filtered correctly
231
232my $o = ppport(qw(--copy=a));
233ok($o =~ /^Scanning.*MyExt\.xs/mi);
234ok($o =~ /Analyzing.*MyExt\.xs/mi);
235ok(matches($o, '^Scanning', 'm'), 1);
236ok($o =~ /^Needs to include.*ppport\.h/m);
237ok($o !~ /^Uses grok_bin/m);
238ok($o !~ /^Uses newSVpv/m);
239ok($o =~ /Uses 1 C\+\+ style comment/m);
240ok(eq_files('MyExt.xsa', 'MyExt.ra'));
241
242# check if C++ are left untouched with --cplusplus
243
244$o = ppport(qw(--copy=b --cplusplus));
245ok($o =~ /^Scanning.*MyExt\.xs/mi);
246ok($o =~ /Analyzing.*MyExt\.xs/mi);
247ok(matches($o, '^Scanning', 'm'), 1);
248ok($o =~ /^Needs to include.*ppport\.h/m);
249ok($o !~ /^Uses grok_bin/m);
250ok($o !~ /^Uses newSVpv/m);
251ok($o !~ /Uses \d+ C\+\+ style comment/m);
252ok(eq_files('MyExt.xsb', 'MyExt.rb'));
253
254unlink qw(MyExt.xsa MyExt.xsb);
255
256---------------------------- MyExt.xs -----------------------------------------
257
258newSVuv();
259    // newSVpv();
260  XPUSHs(foo);
261/* grok_bin(); */
262
263---------------------------- MyExt.ra -----------------------------------------
264
265#include "ppport.h"
266newSVuv();
267    /* newSVpv(); */
268  XPUSHs(foo);
269/* grok_bin(); */
270
271---------------------------- MyExt.rb -----------------------------------------
272
273#include "ppport.h"
274newSVuv();
275    // newSVpv();
276  XPUSHs(foo);
277/* grok_bin(); */
278
279===============================================================================
280
281my $o = ppport(qw(--nochanges file1.xs));
282ok($o =~ /^Scanning.*file1\.xs/mi);
283ok($o =~ /Analyzing.*file1\.xs/mi);
284ok($o !~ /^Scanning.*file2\.xs/mi);
285ok($o =~ /^Uses newCONSTSUB/m);
286ok($o =~ /^Uses PL_expect/m);
287ok($o =~ /^Uses SvPV_nolen.*depends.*sv_2pv_flags/m);
288ok($o =~ /WARNING: PL_expect/m);
289ok($o =~ /hint for newCONSTSUB/m);
290ok($o =~ /^Analysis completed \(1 warning\)/m);
291ok($o =~ /^Looks good/m);
292
293$o = ppport(qw(--nochanges --nohints file1.xs));
294ok($o =~ /^Scanning.*file1\.xs/mi);
295ok($o =~ /Analyzing.*file1\.xs/mi);
296ok($o !~ /^Scanning.*file2\.xs/mi);
297ok($o =~ /^Uses newCONSTSUB/m);
298ok($o =~ /^Uses PL_expect/m);
299ok($o =~ /^Uses SvPV_nolen.*depends.*sv_2pv_flags/m);
300ok($o =~ /WARNING: PL_expect/m);
301ok($o !~ /hint for newCONSTSUB/m);
302ok($o =~ /^Analysis completed \(1 warning\)/m);
303ok($o =~ /^Looks good/m);
304
305$o = ppport(qw(--nochanges --nohints --nodiag file1.xs));
306ok($o =~ /^Scanning.*file1\.xs/mi);
307ok($o =~ /Analyzing.*file1\.xs/mi);
308ok($o !~ /^Scanning.*file2\.xs/mi);
309ok($o !~ /^Uses newCONSTSUB/m);
310ok($o !~ /^Uses PL_expect/m);
311ok($o !~ /^Uses SvPV_nolen/m);
312ok($o =~ /WARNING: PL_expect/m);
313ok($o !~ /hint for newCONSTSUB/m);
314ok($o =~ /^Analysis completed \(1 warning\)/m);
315ok($o =~ /^Looks good/m);
316
317$o = ppport(qw(--nochanges --quiet file1.xs));
318ok($o =~ /^\s*$/);
319
320$o = ppport(qw(--nochanges file2.xs));
321ok($o =~ /^Scanning.*file2\.xs/mi);
322ok($o =~ /Analyzing.*file2\.xs/mi);
323ok($o !~ /^Scanning.*file1\.xs/mi);
324ok($o =~ /^Uses mXPUSHp/m);
325ok($o =~ /^Needs to include.*ppport\.h/m);
326ok($o !~ /^Looks good/m);
327ok($o =~ /^1 potentially required change detected/m);
328
329$o = ppport(qw(--nochanges --nohints file2.xs));
330ok($o =~ /^Scanning.*file2\.xs/mi);
331ok($o =~ /Analyzing.*file2\.xs/mi);
332ok($o !~ /^Scanning.*file1\.xs/mi);
333ok($o =~ /^Uses mXPUSHp/m);
334ok($o =~ /^Needs to include.*ppport\.h/m);
335ok($o !~ /^Looks good/m);
336ok($o =~ /^1 potentially required change detected/m);
337
338$o = ppport(qw(--nochanges --nohints --nodiag file2.xs));
339ok($o =~ /^Scanning.*file2\.xs/mi);
340ok($o =~ /Analyzing.*file2\.xs/mi);
341ok($o !~ /^Scanning.*file1\.xs/mi);
342ok($o !~ /^Uses mXPUSHp/m);
343ok($o !~ /^Needs to include.*ppport\.h/m);
344ok($o !~ /^Looks good/m);
345ok($o =~ /^1 potentially required change detected/m);
346
347$o = ppport(qw(--nochanges --quiet file2.xs));
348ok($o =~ /^\s*$/);
349
350---------------------------- file1.xs -----------------------------------------
351
352#define NEED_newCONSTSUB
353#define NEED_sv_2pv_flags
354#define NEED_PL_parser
355#include "ppport.h"
356
357newCONSTSUB();
358SvPV_nolen();
359PL_expect = 0;
360
361---------------------------- file2.xs -----------------------------------------
362
363mXPUSHp(foo);
364
365===============================================================================
366
367my $o = ppport(qw(--nochanges));
368ok($o =~ /^Scanning.*FooBar\.xs/mi);
369ok($o =~ /Analyzing.*FooBar\.xs/mi);
370ok(matches($o, '^Scanning', 'm'), 1);
371ok($o !~ /^Looks good/m);
372ok($o =~ /^Uses grok_bin/m);
373
374---------------------------- FooBar.xs ----------------------------------------
375
376newSViv();
377XPUSHs(foo);
378grok_bin();
379
380===============================================================================
381
382my $o = ppport(qw(--nochanges));
383ok($o =~ /^Scanning.*First\.xs/mi);
384ok($o =~ /Analyzing.*First\.xs/mi);
385ok($o =~ /^Scanning.*second\.h/mi);
386ok($o =~ /Analyzing.*second\.h/mi);
387ok($o =~ /^Scanning.*sub.*third\.c/mi);
388ok($o =~ /Analyzing.*sub.*third\.c/mi);
389ok($o !~ /^Scanning.*foobar/mi);
390ok(matches($o, '^Scanning', 'm'), 3);
391
392---------------------------- First.xs -----------------------------------------
393
394one
395
396---------------------------- foobar.xyz ---------------------------------------
397
398two
399
400---------------------------- second.h -----------------------------------------
401
402three
403
404---------------------------- sub/third.c --------------------------------------
405
406four
407
408===============================================================================
409
410my $o = ppport(qw(--nochanges));
411ok($o =~ /Possibly wrong #define NEED_foobar in.*test.xs/i);
412
413---------------------------- test.xs ------------------------------------------
414
415#define NEED_foobar
416
417===============================================================================
418
419# And now some complex "real-world" example
420
421my $o = ppport(qw(--copy=f));
422for (qw(main.xs mod1.c mod2.c mod3.c mod4.c mod5.c)) {
423  ok($o =~ /^Scanning.*\Q$_\E/mi);
424  ok($o =~ /Analyzing.*\Q$_\E/i);
425}
426ok(matches($o, '^Scanning', 'm'), 6);
427
428ok(matches($o, '^Writing copy of', 'm'), 5);
429ok(!-e "mod5.cf");
430
431for (qw(main.xs mod1.c mod2.c mod3.c mod4.c)) {
432  ok($o =~ /^Writing copy of.*\Q$_\E.*with changes/mi);
433  ok(-e "${_}f");
434  ok(eq_files("${_}f", "${_}r"));
435  unlink "${_}f";
436}
437
438---------------------------- main.xs ------------------------------------------
439
440#include "EXTERN.h"
441#include "perl.h"
442#include "XSUB.h"
443
444#define NEED_newCONSTSUB
445#define NEED_grok_hex_GLOBAL
446#include "ppport.h"
447
448newCONSTSUB();
449grok_hex();
450Perl_grok_bin(aTHX_ foo, bar);
451
452/* some comment */
453
454perl_eval_pv();
455grok_bin();
456Perl_grok_bin(bar, sv_no);
457
458---------------------------- mod1.c -------------------------------------------
459
460#include "EXTERN.h"
461#include "perl.h"
462#include "XSUB.h"
463
464#define NEED_grok_bin_GLOBAL
465#define NEED_newCONSTSUB
466#include "ppport.h"
467
468newCONSTSUB();
469grok_bin();
470{
471  Perl_croak ("foo");
472  Perl_sv_catpvf();  /* I know it's wrong ;-) */
473}
474
475---------------------------- mod2.c -------------------------------------------
476
477#include "EXTERN.h"
478#include "perl.h"
479#include "XSUB.h"
480
481#define NEED_eval_pv
482#include "ppport.h"
483
484newSViv();
485
486/*
487   eval_pv();
488*/
489
490---------------------------- mod3.c -------------------------------------------
491
492#include "EXTERN.h"
493#include "perl.h"
494#include "XSUB.h"
495
496grok_oct();
497eval_pv();
498
499---------------------------- mod4.c -------------------------------------------
500
501#include "EXTERN.h"
502#include "perl.h"
503#include "XSUB.h"
504
505START_MY_CXT;
506
507---------------------------- mod5.c -------------------------------------------
508
509#include "EXTERN.h"
510#include "perl.h"
511#include "XSUB.h"
512
513#include "ppport.h"
514call_pv();
515
516---------------------------- main.xsr -----------------------------------------
517
518#include "EXTERN.h"
519#include "perl.h"
520#include "XSUB.h"
521
522#define NEED_eval_pv_GLOBAL
523#define NEED_grok_hex
524#define NEED_newCONSTSUB_GLOBAL
525#define NEED_sv_2pv_flags_GLOBAL
526#include "ppport.h"
527
528newCONSTSUB();
529grok_hex();
530grok_bin(foo, bar);
531
532/* some comment */
533
534eval_pv();
535grok_bin();
536grok_bin(bar, PL_sv_no);
537
538---------------------------- mod1.cr ------------------------------------------
539
540#include "EXTERN.h"
541#include "perl.h"
542#include "XSUB.h"
543
544#define NEED_grok_bin_GLOBAL
545#include "ppport.h"
546
547newCONSTSUB();
548grok_bin();
549{
550  Perl_croak (aTHX_ "foo");
551  Perl_sv_catpvf(aTHX);  /* I know it's wrong ;-) */
552}
553
554---------------------------- mod2.cr ------------------------------------------
555
556#include "EXTERN.h"
557#include "perl.h"
558#include "XSUB.h"
559
560
561newSViv();
562
563/*
564   eval_pv();
565*/
566
567---------------------------- mod3.cr ------------------------------------------
568
569#include "EXTERN.h"
570#include "perl.h"
571#include "XSUB.h"
572#define NEED_grok_oct
573#include "ppport.h"
574
575grok_oct();
576eval_pv();
577
578---------------------------- mod4.cr ------------------------------------------
579
580#include "EXTERN.h"
581#include "perl.h"
582#include "XSUB.h"
583#include "ppport.h"
584
585START_MY_CXT;
586
587===============================================================================
588
589my $o = ppport(qw(--nochanges));
590ok($o =~ /Uses grok_hex/m);
591ok($o !~ /Looks good/m);
592
593$o = ppport(qw(--nochanges --compat-version=5.8.0));
594ok($o !~ /Uses grok_hex/m);
595ok($o =~ /Looks good/m);
596
597---------------------------- FooBar.xs ----------------------------------------
598
599grok_hex();
600
601===============================================================================
602
603my $o = ppport(qw(--nochanges));
604ok($o =~ /Uses SvPVutf8_force, which may not be portable/m);
605
606$o = ppport(qw(--nochanges --compat-version=5.5.3));
607ok($o =~ /Uses SvPVutf8_force, which may not be portable/m);
608
609$o = ppport(qw(--nochanges --compat-version=5.005_03));
610ok($o =~ /Uses SvPVutf8_force, which may not be portable/m);
611
612$o = ppport(qw(--nochanges --compat-version=5.6.0));
613ok($o !~ /Uses SvPVutf8_force/m);
614
615$o = ppport(qw(--nochanges --compat-version=5.006));
616ok($o !~ /Uses SvPVutf8_force/m);
617
618$o = ppport(qw(--nochanges --compat-version=5.999.999));
619ok($o !~ /Uses SvPVutf8_force/m);
620
621$o = ppport(qw(--nochanges --compat-version=6.0.0));
622ok($o =~ /Only Perl 5 is supported/m);
623
624$o = ppport(qw(--nochanges --compat-version=5.1000.999));
625ok($o =~ /Invalid version number: 5.1000.999/m);
626
627$o = ppport(qw(--nochanges --compat-version=5.999.1000));
628ok($o =~ /Invalid version number: 5.999.1000/m);
629
630---------------------------- FooBar.xs ----------------------------------------
631
632SvPVutf8_force();
633
634===============================================================================
635
636my $o = ppport(qw(--nochanges));
637ok($o !~ /potentially required change/);
638ok(matches($o, '^Looks good', 'm'), 2);
639
640---------------------------- FooBar.xs ----------------------------------------
641
642#define NEED_grok_numeric_radix
643#define NEED_grok_number
644#include "ppport.h"
645
646GROK_NUMERIC_RADIX();
647grok_number();
648
649---------------------------- foo.c --------------------------------------------
650
651#include "ppport.h"
652
653call_pv();
654
655===============================================================================
656
657# check --api-info option
658
659my $o = ppport(qw(--api-info=INT2PTR));
660my %found = map {($_ => 1)} $o =~ /^===\s+(\w+)\s+===/mg;
661ok(scalar keys %found, 1);
662ok(exists $found{INT2PTR});
663ok(matches($o, '^Supported at least starting from perl-5\.6\.0\.', 'm'), 1);
664ok(matches($o, '^Support by .*ppport.* provided back to perl-5\.003\.', 'm'), 1);
665
666$o = ppport(qw(--api-info=Zero));
667%found = map {($_ => 1)} $o =~ /^===\s+(\w+)\s+===/mg;
668ok(scalar keys %found, 1);
669ok(exists $found{Zero});
670ok(matches($o, '^No portability information available\.', 'm'), 1);
671
672$o = ppport(qw(--api-info=/Zero/));
673%found = map {($_ => 1)} $o =~ /^===\s+(\w+)\s+===/mg;
674ok(scalar keys %found, 2);
675ok(exists $found{Zero});
676ok(exists $found{ZeroD});
677
678===============================================================================
679
680# check --list-provided option
681
682my @o = ppport(qw(--list-provided));
683my %p;
684my $fail = 0;
685for (@o) {
686  my($name, $flags) = /^(\w+)(?:\s+\[(\w+(?:,\s+\w+)*)\])?$/ or $fail++;
687  exists $p{$name} and $fail++;
688  $p{$name} = defined $flags ? { map { ($_ => 1) } $flags =~ /(\w+)/g } : '';
689}
690ok(@o > 100);
691ok($fail, 0);
692
693ok(exists $p{call_pv});
694ok(not ref $p{call_pv});
695
696ok(exists $p{grok_bin});
697ok(ref $p{grok_bin}, 'HASH');
698ok(scalar keys %{$p{grok_bin}}, 2);
699ok($p{grok_bin}{explicit});
700ok($p{grok_bin}{depend});
701
702ok(exists $p{gv_stashpvn});
703ok(ref $p{gv_stashpvn}, 'HASH');
704ok(scalar keys %{$p{gv_stashpvn}}, 2);
705ok($p{gv_stashpvn}{depend});
706ok($p{gv_stashpvn}{hint});
707
708ok(exists $p{sv_catpvf_mg});
709ok(ref $p{sv_catpvf_mg}, 'HASH');
710ok(scalar keys %{$p{sv_catpvf_mg}}, 2);
711ok($p{sv_catpvf_mg}{explicit});
712ok($p{sv_catpvf_mg}{depend});
713
714ok(exists $p{PL_signals});
715ok(ref $p{PL_signals}, 'HASH');
716ok(scalar keys %{$p{PL_signals}}, 1);
717ok($p{PL_signals}{explicit});
718
719===============================================================================
720
721# check --list-unsupported option
722
723my @o = ppport(qw(--list-unsupported));
724my %p;
725my $fail = 0;
726for (@o) {
727  my($name, $ver) = /^(\w+)\s*\.+\s*([\d._]+)$/ or $fail++;
728  exists $p{$name} and $fail++;
729  $p{$name} = $ver;
730}
731ok(@o > 100);
732ok($fail, 0);
733
734ok(exists $p{utf8_distance});
735ok($p{utf8_distance}, '5.6.0');
736
737ok(exists $p{save_generic_svref});
738ok($p{save_generic_svref}, '5.005_03');
739
740===============================================================================
741
742# check --nofilter option
743
744my $o = ppport(qw(--nochanges));
745ok($o =~ /^Scanning.*foo\.cpp/mi);
746ok($o =~ /Analyzing.*foo\.cpp/mi);
747ok(matches($o, '^Scanning', 'm'), 1);
748ok(matches($o, 'Analyzing', 'm'), 1);
749
750$o = ppport(qw(--nochanges foo.cpp foo.o Makefile.PL));
751ok($o =~ /Skipping the following files \(use --nofilter to avoid this\):/m);
752ok(matches($o, '^\|\s+foo\.o', 'mi'), 1);
753ok(matches($o, '^\|\s+Makefile\.PL', 'mi'), 1);
754ok($o =~ /^Scanning.*foo\.cpp/mi);
755ok($o =~ /Analyzing.*foo\.cpp/mi);
756ok(matches($o, '^Scanning', 'm'), 1);
757ok(matches($o, 'Analyzing', 'm'), 1);
758
759$o = ppport(qw(--nochanges --nofilter foo.cpp foo.o Makefile.PL));
760ok($o =~ /^Scanning.*foo\.cpp/mi);
761ok($o =~ /Analyzing.*foo\.cpp/mi);
762ok($o =~ /^Scanning.*foo\.o/mi);
763ok($o =~ /Analyzing.*foo\.o/mi);
764ok($o =~ /^Scanning.*Makefile/mi);
765ok($o =~ /Analyzing.*Makefile/mi);
766ok(matches($o, '^Scanning', 'm'), 3);
767ok(matches($o, 'Analyzing', 'm'), 3);
768
769---------------------------- foo.cpp ------------------------------------------
770
771newSViv();
772
773---------------------------- foo.o --------------------------------------------
774
775newSViv();
776
777---------------------------- Makefile.PL --------------------------------------
778
779newSViv();
780
781===============================================================================
782
783# check if explicit variables are handled propery
784
785my $o = ppport(qw(--copy=a));
786ok($o =~ /^Needs to include.*ppport\.h/m);
787ok($o =~ /^Uses PL_signals/m);
788ok($o =~ /^File needs PL_signals, adding static request/m);
789ok(eq_files('MyExt.xsa', 'MyExt.ra'));
790
791unlink qw(MyExt.xsa);
792
793---------------------------- MyExt.xs -----------------------------------------
794
795PL_signals = 123;
796if (PL_signals == 42)
797  foo();
798
799---------------------------- MyExt.ra -----------------------------------------
800
801#define NEED_PL_signals
802#include "ppport.h"
803PL_signals = 123;
804if (PL_signals == 42)
805  foo();
806
807===============================================================================
808
809my $o = ppport(qw(--nochanges file.xs));
810ok($o =~ /^Uses PL_copline/m);
811ok($o =~ /WARNING: PL_copline/m);
812ok($o =~ /^Uses SvUOK/m);
813ok($o =~ /WARNING: Uses SvUOK, which may not be portable/m);
814ok($o =~ /^Analysis completed \(2 warnings\)/m);
815ok($o =~ /^Looks good/m);
816
817$o = ppport(qw(--nochanges --compat-version=5.8.0 file.xs));
818ok($o =~ /^Uses PL_copline/m);
819ok($o =~ /WARNING: PL_copline/m);
820ok($o !~ /WARNING: Uses SvUOK, which may not be portable/m);
821ok($o =~ /^Analysis completed \(1 warning\)/m);
822ok($o =~ /^Looks good/m);
823
824---------------------------- file.xs -----------------------------------------
825
826#define NEED_PL_parser
827#include "ppport.h"
828SvUOK
829PL_copline
830
831===============================================================================
832
833my $o = ppport(qw(--copy=f));
834
835for (qw(file.xs)) {
836  ok($o =~ /^Writing copy of.*\Q$_\E.*with changes/mi);
837  ok(-e "${_}f");
838  ok(eq_files("${_}f", "${_}r"));
839  unlink "${_}f";
840}
841
842---------------------------- file.xs -----------------------------------------
843
844a_string = "sv_undef"
845a_char = 'sv_yes'
846#define SOMETHING defgv
847/* C-comment: sv_tainted */
848#
849# This is just a big XS comment using sv_no
850#
851/* The following, is NOT an XS comment! */
852#  define SOMETHING_ELSE defgv + \
853                         sv_undef
854
855---------------------------- file.xsr -----------------------------------------
856
857#include "ppport.h"
858a_string = "sv_undef"
859a_char = 'sv_yes'
860#define SOMETHING PL_defgv
861/* C-comment: sv_tainted */
862#
863# This is just a big XS comment using sv_no
864#
865/* The following, is NOT an XS comment! */
866#  define SOMETHING_ELSE PL_defgv + \
867                         PL_sv_undef
868
869===============================================================================
870
871my $o = ppport(qw(--copy=f));
872
873for (qw(file.xs)) {
874  ok($o =~ /^Writing copy of.*\Q$_\E.*with changes/mi);
875  ok(-e "${_}f");
876  ok(eq_files("${_}f", "${_}r"));
877  unlink "${_}f";
878}
879
880---------------------------- file.xs -----------------------------------------
881
882#define NEED_sv_2pv_flags
883#define NEED_vnewSVpvf
884#define NEED_warner
885#include "ppport.h"
886Perl_croak_nocontext("foo");
887Perl_croak("bar");
888croak("foo");
889croak_nocontext("foo");
890Perl_warner_nocontext("foo");
891Perl_warner("foo");
892warner_nocontext("foo");
893warner("foo");
894
895---------------------------- file.xsr -----------------------------------------
896
897#define NEED_sv_2pv_flags
898#define NEED_vnewSVpvf
899#define NEED_warner
900#include "ppport.h"
901Perl_croak_nocontext("foo");
902Perl_croak(aTHX_ "bar");
903croak("foo");
904croak_nocontext("foo");
905Perl_warner_nocontext("foo");
906Perl_warner(aTHX_ "foo");
907warner_nocontext("foo");
908warner("foo");
909