Imported Upstream version 1.23
Lucas Kanashiro
8 years ago
19 | 19 | "Ilya Martynov <ilya\@martynov.org>" |
20 | 20 | ], |
21 | 21 | "dist_name" => "Params-Validate", |
22 | "dist_version" => "1.22", | |
22 | "dist_version" => "1.23", | |
23 | 23 | "license" => "artistic_2", |
24 | 24 | "module_name" => "Params::Validate", |
25 | 25 | "recursive_test_files" => 1, |
26 | 26 | "requires" => { |
27 | 27 | "Carp" => 0, |
28 | 28 | "Exporter" => 0, |
29 | "JSON::PP" => "2.27300", | |
30 | 29 | "Module::Implementation" => 0, |
31 | 30 | "Scalar::Util" => "1.10", |
32 | 31 | "XSLoader" => 0, |
0 | # CONTRIBUTING | |
1 | ||
2 | Thank you for considering contributing to this distribution. This file | |
3 | contains instructions that will help you work with the source code. | |
4 | ||
5 | Please note that if you have any questions or difficulties, you can reach the | |
6 | maintainer(s) through the bug queue described later in this document | |
7 | (preferred), or by emailing the releaser directly. You are not required to | |
8 | follow any of the steps in this document to submit a patch or bug report; | |
9 | these are just recommendations, intended to help you (and help us help you | |
10 | faster). | |
11 | ||
12 | This distribution has a TODO file in the repository; you may want to check | |
13 | there to see if your issue or patch idea is mentioned. | |
14 | ||
15 | ||
16 | The distribution is managed with | |
17 | [Dist::Zilla](https://metacpan.org/release/Dist-Zilla). | |
18 | ||
19 | However, you can still compile and test the code with the `Makefile.PL` in the | |
20 | repository: | |
21 | ||
22 | perl Makefile.PL | |
23 | make | |
24 | make test | |
25 | ||
26 | As well as: | |
27 | ||
28 | $ prove -bvr t | |
29 | ||
30 | or | |
31 | ||
32 | $ perl -Mblib t/some_test_file.t | |
33 | ||
34 | You may need to satisfy some dependencies. The easiest way to satisfy | |
35 | dependencies is to install the last release. This is available at | |
36 | https://metacpan.org/release/Params-Validate | |
37 | ||
38 | If you use cpanminus, you can do it without downloading the tarball first: | |
39 | ||
40 | $ cpanm --reinstall --installdeps --with-recommends Params::Validate | |
41 | ||
42 | Dist::Zilla is a very powerful authoring tool, but requires a number of | |
43 | author-specific plugins. If you would like to use it for contributing, install | |
44 | it from CPAN, then run one of the following commands, depending on your CPAN | |
45 | client: | |
46 | ||
47 | $ cpan `dzil authordeps --missing` | |
48 | ||
49 | or | |
50 | ||
51 | $ dzil authordeps --missing | cpanm | |
52 | ||
53 | They may also be additional requirements not needed by the dzil build which | |
54 | are needed for tests or other development: | |
55 | ||
56 | $ cpan `dzil listdeps --author --missing` | |
57 | ||
58 | or | |
59 | ||
60 | $ dzil listdeps --author --missing | cpanm | |
61 | ||
62 | Or, you can use the 'dzil stale' command to install all requirements at once: | |
63 | ||
64 | $ cpan Dist::Zilla::App::Command::stale | |
65 | $ cpan `dzil stale --all` | |
66 | ||
67 | or | |
68 | ||
69 | $ cpanm Dist::Zilla::App::Command::stale | |
70 | $ dzil stale --all | cpanm | |
71 | ||
72 | You can also do this via cpanm directly: | |
73 | ||
74 | $ cpanm --reinstall --installdeps --with-develop --with-recommends Params::Validate | |
75 | ||
76 | Once installed, here are some dzil commands you might try: | |
77 | ||
78 | $ dzil build | |
79 | $ dzil test | |
80 | $ dzil test --release | |
81 | $ dzil xtest | |
82 | $ dzil listdeps --json | |
83 | $ dzil build --notgz | |
84 | ||
85 | You can learn more about Dist::Zilla at http://dzil.org/. | |
86 | ||
87 | The code for this distribution is [hosted at GitHub](https://github.com/autarch/Params-Validate). | |
88 | ||
89 | You can submit code changes by forking the repository, pushing your code | |
90 | changes to your clone, and then submitting a pull request. Detailed | |
91 | instructions for doing that is available here: | |
92 | ||
93 | https://help.github.com/articles/creating-a-pull-request | |
94 | ||
95 | If you have found a bug, but do not have an accompanying patch to fix it, you | |
96 | can submit an issue report [via the web](http://rt.cpan.org/Public/Dist/Display.html?Name=Params-Validate) | |
97 | or [via email](bug-params-validate@rt.cpan.org. | |
98 | This is a good place to send your questions about the usage of this distribution. | |
99 | ||
100 | ## Travis | |
101 | ||
102 | All pull requests for this distribution will be automatically tested by | |
103 | [Travis](https://travis-ci.org/) and the build status will be reported on the | |
104 | pull request page. If your build fails, please take a look at the output. | |
105 | ||
106 | ## Tidyall | |
107 | ||
108 | This distribution uses | |
109 | [Code::TidyAll](https://metacpan.org/release/Code-TidyAll) to enforce a | |
110 | uniform coding style. This is tested as part of the author testing. You can | |
111 | install and run tidyall by running the following commands: | |
112 | ||
113 | $ cpanm Code::TidyAll | |
114 | $ tidyall -a | |
115 | ||
116 | Please run this before committing your changes and address any issues it | |
117 | brings up. | |
118 | ||
119 | ## Contributor Names | |
120 | ||
121 | If you send me a patch or pull request, your name and email address will be | |
122 | included in the documentation as a contributor (using the attribution on the | |
123 | commit or patch), unless you specifically request for it not to be. If you | |
124 | wish to be listed under a different name or address, you should submit a pull | |
125 | request to the .mailmap file to contain the correct mapping. | |
126 | ||
127 | This file was generated via Dist::Zilla::Plugin::GenerateFile::FromShareDir 0.009 from a | |
128 | template file originating in Dist-Zilla-PluginBundle-DROLSKY-0.45. |
0 | 1.23 2016-03-26 | |
1 | ||
2 | - Fixed some Perl stack corruption bugs. Based on a proposed PR from Tony Cook | |
3 | plus some additional changes. GH #8. | |
4 | ||
5 | - Fixed tests with Carp 1.01 (shipped with Perl 5.8.3). Patch by Andreas | |
6 | Koenig. RT #113318. | |
7 | ||
8 | ||
0 | 9 | 1.22 2016-02-13 |
1 | 10 | |
2 | 11 | - Fixed a bug when a callback failed but did not die. The resulting error |
0 | 0 | # This file was automatically generated by Dist::Zilla::Plugin::Manifest v5.043. |
1 | 1 | Build.PL |
2 | CONTRIBUTING.md | |
2 | 3 | Changes |
3 | 4 | INSTALL |
4 | 5 | LICENSE |
62 | 63 | t/39-reentrant.t |
63 | 64 | t/author-00-compile.t |
64 | 65 | t/author-eol.t |
66 | t/author-memory-leak.t | |
65 | 67 | t/author-mojibake.t |
66 | 68 | t/author-no-tabs.t |
67 | 69 | t/author-pod-spell.t |
68 | 70 | t/author-pod-syntax.t |
71 | t/author-pp-01-validate.t | |
72 | t/author-pp-02-noop.t | |
73 | t/author-pp-04-defaults.t | |
74 | t/author-pp-05-noop_default.t | |
75 | t/author-pp-06-options.t | |
76 | t/author-pp-07-with.t | |
77 | t/author-pp-08-noop_with.t | |
78 | t/author-pp-09-regex.t | |
79 | t/author-pp-10-noop_regex.t | |
80 | t/author-pp-11-cb.t | |
81 | t/author-pp-12-noop_cb.t | |
82 | t/author-pp-13-taint.t | |
83 | t/author-pp-14-no_validate.t | |
84 | t/author-pp-15-case.t | |
85 | t/author-pp-16-normalize.t | |
86 | t/author-pp-17-callbacks.t | |
87 | t/author-pp-18-depends.t | |
88 | t/author-pp-19-untaint.t | |
89 | t/author-pp-21-can.t | |
90 | t/author-pp-22-overload-can-bug.t | |
91 | t/author-pp-23-readonly.t | |
92 | t/author-pp-24-tied.t | |
93 | t/author-pp-25-undef-regex.t | |
94 | t/author-pp-26-isa.t | |
95 | t/author-pp-27-string-as-type.t | |
96 | t/author-pp-28-readonly-return.t | |
97 | t/author-pp-29-taint-mode.t | |
98 | t/author-pp-30-hashref-alteration.t | |
99 | t/author-pp-31-incorrect-spelling.t | |
100 | t/author-pp-32-regex-as-value.t | |
101 | t/author-pp-33-keep-errsv.t | |
102 | t/author-pp-34-recursive-validation.t | |
103 | t/author-pp-35-default-xs-bug.t | |
104 | t/author-pp-36-large-arrays.t | |
105 | t/author-pp-37-exports.t | |
106 | t/author-pp-38-callback-message.t | |
107 | t/author-pp-39-reentrant.t | |
108 | t/author-pp-is-loaded.t | |
109 | t/author-xs-is-loaded.t | |
110 | t/author-xs-segfault.t | |
111 | t/author-xs-stack-realloc.t | |
69 | 112 | t/lib/PVTests.pm |
70 | 113 | t/lib/PVTests/Callbacks.pm |
71 | 114 | t/lib/PVTests/Defaults.pm |
73 | 116 | t/lib/PVTests/Standard.pm |
74 | 117 | t/lib/PVTests/With.pm |
75 | 118 | t/release-cpan-changes.t |
76 | t/release-memory-leak.t | |
77 | 119 | t/release-meta-json.t |
78 | 120 | t/release-pod-coverage.t |
79 | 121 | t/release-pod-linkcheck.t |
80 | 122 | t/release-pod-no404s.t |
81 | 123 | t/release-portability.t |
82 | t/release-pp-01-validate.t | |
83 | t/release-pp-02-noop.t | |
84 | t/release-pp-04-defaults.t | |
85 | t/release-pp-05-noop_default.t | |
86 | t/release-pp-06-options.t | |
87 | t/release-pp-07-with.t | |
88 | t/release-pp-08-noop_with.t | |
89 | t/release-pp-09-regex.t | |
90 | t/release-pp-10-noop_regex.t | |
91 | t/release-pp-11-cb.t | |
92 | t/release-pp-12-noop_cb.t | |
93 | t/release-pp-13-taint.t | |
94 | t/release-pp-14-no_validate.t | |
95 | t/release-pp-15-case.t | |
96 | t/release-pp-16-normalize.t | |
97 | t/release-pp-17-callbacks.t | |
98 | t/release-pp-18-depends.t | |
99 | t/release-pp-19-untaint.t | |
100 | t/release-pp-21-can.t | |
101 | t/release-pp-22-overload-can-bug.t | |
102 | t/release-pp-23-readonly.t | |
103 | t/release-pp-24-tied.t | |
104 | t/release-pp-25-undef-regex.t | |
105 | t/release-pp-26-isa.t | |
106 | t/release-pp-27-string-as-type.t | |
107 | t/release-pp-28-readonly-return.t | |
108 | t/release-pp-29-taint-mode.t | |
109 | t/release-pp-30-hashref-alteration.t | |
110 | t/release-pp-31-incorrect-spelling.t | |
111 | t/release-pp-32-regex-as-value.t | |
112 | t/release-pp-33-keep-errsv.t | |
113 | t/release-pp-34-recursive-validation.t | |
114 | t/release-pp-35-default-xs-bug.t | |
115 | t/release-pp-36-large-arrays.t | |
116 | t/release-pp-37-exports.t | |
117 | t/release-pp-38-callback-message.t | |
118 | t/release-pp-39-reentrant.t | |
119 | t/release-pp-is-loaded.t | |
120 | 124 | t/release-synopsis.t |
121 | t/release-xs-is-loaded.t | |
122 | t/release-xs-segfault.t | |
123 | t/release-xs-stack-realloc.t | |
124 | 125 | tidyall.ini |
125 | 126 | weaver.ini |
22 | 22 | "configure" : { |
23 | 23 | "requires" : { |
24 | 24 | "Module::Build" : "0.28" |
25 | }, | |
26 | "suggests" : { | |
27 | "JSON::PP" : "2.27300" | |
25 | 28 | } |
26 | 29 | }, |
27 | 30 | "develop" : { |
54 | 57 | "requires" : { |
55 | 58 | "Carp" : "0", |
56 | 59 | "Exporter" : "0", |
57 | "JSON::PP" : "2.27300", | |
58 | 60 | "Module::Implementation" : "0", |
59 | 61 | "Scalar::Util" : "1.10", |
60 | 62 | "XSLoader" : "0", |
87 | 89 | "provides" : { |
88 | 90 | "Params::Validate" : { |
89 | 91 | "file" : "lib/Params/Validate.pm", |
90 | "version" : "1.22" | |
92 | "version" : "1.23" | |
91 | 93 | }, |
92 | 94 | "Params::Validate::Constants" : { |
93 | 95 | "file" : "lib/Params/Validate/Constants.pm", |
94 | "version" : "1.22" | |
96 | "version" : "1.23" | |
95 | 97 | }, |
96 | 98 | "Params::Validate::PP" : { |
97 | 99 | "file" : "lib/Params/Validate/PP.pm", |
98 | "version" : "1.22" | |
100 | "version" : "1.23" | |
99 | 101 | }, |
100 | 102 | "Params::Validate::XS" : { |
101 | 103 | "file" : "lib/Params/Validate/XS.pm", |
102 | "version" : "1.22" | |
104 | "version" : "1.23" | |
103 | 105 | } |
104 | 106 | }, |
105 | 107 | "release_status" : "stable", |
115 | 117 | "web" : "https://github.com/autarch/Params-Validate" |
116 | 118 | } |
117 | 119 | }, |
118 | "version" : "1.22", | |
120 | "version" : "1.23", | |
119 | 121 | "x_Dist_Zilla" : { |
120 | 122 | "perl" : { |
121 | 123 | "version" : "5.022001" |
142 | 144 | "Dist::Zilla::Plugin::GatherDir" : { |
143 | 145 | "exclude_filename" : [ |
144 | 146 | "Build.PL", |
147 | "CONTRIBUTING.md", | |
145 | 148 | "LICENSE", |
146 | 149 | "Makefile.PL", |
147 | 150 | "README.md", |
148 | "cpanfile" | |
151 | "cpanfile", | |
152 | "ppport.h" | |
149 | 153 | ], |
150 | 154 | "exclude_match" : [], |
151 | 155 | "follow_symlinks" : 0, |
238 | 242 | "modules" : [], |
239 | 243 | "phase" : "release", |
240 | 244 | "skip" : [ |
245 | "Dist::Zilla::Plugin::DROLSKY::CheckChangesHasContent", | |
241 | 246 | "Dist::Zilla::Plugin::DROLSKY::Contributors", |
247 | "Dist::Zilla::Plugin::DROLSKY::Git::CheckFor::CorrectBranch", | |
242 | 248 | "Dist::Zilla::Plugin::DROLSKY::License", |
243 | 249 | "Dist::Zilla::Plugin::DROLSKY::TidyAll", |
244 | 250 | "Dist::Zilla::Plugin::DROLSKY::VersionProvider" |
247 | 253 | }, |
248 | 254 | "name" : "@DROLSKY/PromptIfStale", |
249 | 255 | "version" : "0.047" |
250 | }, | |
251 | { | |
252 | "class" : "Dist::Zilla::Plugin::ReadmeAnyFromPod", | |
253 | "config" : { | |
254 | "Dist::Zilla::Role::FileWatcher" : { | |
255 | "version" : "0.006" | |
256 | } | |
257 | }, | |
258 | "name" : "@DROLSKY/README.md in build", | |
259 | "version" : "0.150250" | |
260 | }, | |
261 | { | |
262 | "class" : "Dist::Zilla::Plugin::ReadmeAnyFromPod", | |
263 | "config" : { | |
264 | "Dist::Zilla::Role::FileWatcher" : { | |
265 | "version" : "0.006" | |
266 | } | |
267 | }, | |
268 | "name" : "@DROLSKY/README.md in root", | |
269 | "version" : "0.150250" | |
270 | 256 | }, |
271 | 257 | { |
272 | 258 | "class" : "Dist::Zilla::Plugin::Test::Pod::Coverage::Configurable", |
293 | 279 | "SCALARREF", |
294 | 280 | "ValidatePos", |
295 | 281 | "baz", |
282 | "drolsky", | |
296 | 283 | "onwards", |
297 | 284 | "pre", |
298 | 285 | "runtime" |
306 | 293 | { |
307 | 294 | "class" : "Dist::Zilla::Plugin::Test::ReportPrereqs", |
308 | 295 | "name" : "@DROLSKY/Test::ReportPrereqs", |
309 | "version" : "0.021" | |
296 | "version" : "0.024" | |
310 | 297 | }, |
311 | 298 | { |
312 | 299 | "class" : "Dist::Zilla::Plugin::ManifestSkip", |
364 | 351 | "version" : "5.043" |
365 | 352 | }, |
366 | 353 | { |
354 | "class" : "Dist::Zilla::Plugin::GenerateFile::FromShareDir", | |
355 | "config" : { | |
356 | "Dist::Zilla::Plugin::GenerateFile::FromShareDir" : { | |
357 | "destination_filename" : "CONTRIBUTING.md", | |
358 | "dist" : "Dist-Zilla-PluginBundle-DROLSKY", | |
359 | "encoding" : "UTF-8", | |
360 | "has_xs" : "", | |
361 | "location" : "build", | |
362 | "source_filename" : "CONTRIBUTING.md" | |
363 | }, | |
364 | "Dist::Zilla::Role::RepoFileInjector" : { | |
365 | "allow_overwrite" : 1, | |
366 | "repo_root" : ".", | |
367 | "version" : "0.005" | |
368 | } | |
369 | }, | |
370 | "name" : "@DROLSKY/generate CONTRIBUTING", | |
371 | "version" : "0.009" | |
372 | }, | |
373 | { | |
367 | 374 | "class" : "Dist::Zilla::Plugin::CheckPrereqsIndexed", |
368 | 375 | "name" : "@DROLSKY/CheckPrereqsIndexed", |
369 | 376 | "version" : "0.017" |
374 | 381 | "version" : "5.043" |
375 | 382 | }, |
376 | 383 | { |
384 | "class" : "Dist::Zilla::Plugin::DROLSKY::CheckChangesHasContent", | |
385 | "name" : "@DROLSKY/DROLSKY::CheckChangesHasContent", | |
386 | "version" : "0.45" | |
387 | }, | |
388 | { | |
377 | 389 | "class" : "Dist::Zilla::Plugin::DROLSKY::Contributors", |
378 | 390 | "name" : "@DROLSKY/DROLSKY::Contributors", |
379 | "version" : "0.42" | |
391 | "version" : "0.45" | |
380 | 392 | }, |
381 | 393 | { |
382 | 394 | "class" : "Dist::Zilla::Plugin::DROLSKY::License", |
383 | 395 | "name" : "@DROLSKY/DROLSKY::License", |
384 | "version" : "0.42" | |
396 | "version" : "0.45" | |
385 | 397 | }, |
386 | 398 | { |
387 | 399 | "class" : "Dist::Zilla::Plugin::DROLSKY::TidyAll", |
388 | 400 | "name" : "@DROLSKY/DROLSKY::TidyAll", |
389 | "version" : "0.42" | |
401 | "version" : "0.45" | |
390 | 402 | }, |
391 | 403 | { |
392 | 404 | "class" : "Dist::Zilla::Plugin::DROLSKY::VersionProvider", |
393 | 405 | "name" : "@DROLSKY/DROLSKY::VersionProvider", |
394 | "version" : "0.42" | |
406 | "version" : "0.45" | |
395 | 407 | }, |
396 | 408 | { |
397 | 409 | "class" : "Dist::Zilla::Plugin::DROLSKY::Git::CheckFor::CorrectBranch", |
401 | 413 | } |
402 | 414 | }, |
403 | 415 | "name" : "@DROLSKY/DROLSKY::Git::CheckFor::CorrectBranch", |
404 | "version" : "0.42" | |
416 | "version" : "0.45" | |
405 | 417 | }, |
406 | 418 | { |
407 | 419 | "class" : "Dist::Zilla::Plugin::Git::CheckFor::MergeConflicts", |
426 | 438 | } |
427 | 439 | }, |
428 | 440 | "name" : "@DROLSKY/Git::Contributors", |
429 | "version" : "0.018" | |
441 | "version" : "0.020" | |
430 | 442 | }, |
431 | 443 | { |
432 | 444 | "class" : "Dist::Zilla::Plugin::InstallGuide", |
436 | 448 | { |
437 | 449 | "class" : "Dist::Zilla::Plugin::Meta::Contributors", |
438 | 450 | "name" : "@DROLSKY/Meta::Contributors", |
439 | "version" : "0.002" | |
451 | "version" : "0.003" | |
440 | 452 | }, |
441 | 453 | { |
442 | 454 | "class" : "Dist::Zilla::Plugin::MetaConfig", |
452 | 464 | "class" : "Dist::Zilla::Plugin::SurgicalPodWeaver", |
453 | 465 | "config" : { |
454 | 466 | "Dist::Zilla::Plugin::PodWeaver" : { |
467 | "config_plugins" : [ | |
468 | "@DROLSKY" | |
469 | ], | |
455 | 470 | "finder" : [ |
456 | 471 | ":InstallModules", |
457 | 472 | ":ExecFiles" |
468 | 483 | "version" : "4.012" |
469 | 484 | }, |
470 | 485 | { |
486 | "class" : "Pod::Weaver::Plugin::SingleEncoding", | |
487 | "name" : "@DROLSKY/SingleEncoding", | |
488 | "version" : "4.012" | |
489 | }, | |
490 | { | |
491 | "class" : "Pod::Weaver::Plugin::Transformer", | |
492 | "name" : "@DROLSKY/List", | |
493 | "version" : "4.012" | |
494 | }, | |
495 | { | |
496 | "class" : "Pod::Weaver::Plugin::Transformer", | |
497 | "name" : "@DROLSKY/Verbatim", | |
498 | "version" : "4.012" | |
499 | }, | |
500 | { | |
501 | "class" : "Pod::Weaver::Section::Region", | |
502 | "name" : "@DROLSKY/header", | |
503 | "version" : "4.012" | |
504 | }, | |
505 | { | |
471 | 506 | "class" : "Pod::Weaver::Section::Name", |
472 | "name" : "Name", | |
507 | "name" : "@DROLSKY/Name", | |
473 | 508 | "version" : "4.012" |
474 | 509 | }, |
475 | 510 | { |
476 | 511 | "class" : "Pod::Weaver::Section::Version", |
477 | "name" : "Version", | |
512 | "name" : "@DROLSKY/Version", | |
478 | 513 | "version" : "4.012" |
479 | 514 | }, |
480 | 515 | { |
481 | 516 | "class" : "Pod::Weaver::Section::Region", |
482 | "name" : "prelude", | |
517 | "name" : "@DROLSKY/prelude", | |
483 | 518 | "version" : "4.012" |
484 | 519 | }, |
485 | 520 | { |
493 | 528 | "version" : "4.012" |
494 | 529 | }, |
495 | 530 | { |
531 | "class" : "Pod::Weaver::Section::Generic", | |
532 | "name" : "OVERVIEW", | |
533 | "version" : "4.012" | |
534 | }, | |
535 | { | |
536 | "class" : "Pod::Weaver::Section::Collect", | |
537 | "name" : "ATTRIBUTES", | |
538 | "version" : "4.012" | |
539 | }, | |
540 | { | |
541 | "class" : "Pod::Weaver::Section::Collect", | |
542 | "name" : "METHODS", | |
543 | "version" : "4.012" | |
544 | }, | |
545 | { | |
546 | "class" : "Pod::Weaver::Section::Collect", | |
547 | "name" : "FUNCTIONS", | |
548 | "version" : "4.012" | |
549 | }, | |
550 | { | |
551 | "class" : "Pod::Weaver::Section::Collect", | |
552 | "name" : "TYPES", | |
553 | "version" : "4.012" | |
554 | }, | |
555 | { | |
496 | 556 | "class" : "Pod::Weaver::Section::Leftovers", |
497 | "name" : "Leftovers", | |
557 | "name" : "@DROLSKY/Leftovers", | |
498 | 558 | "version" : "4.012" |
499 | 559 | }, |
500 | 560 | { |
501 | 561 | "class" : "Pod::Weaver::Section::Region", |
502 | "name" : "postlude", | |
503 | "version" : "4.012" | |
562 | "name" : "@DROLSKY/postlude", | |
563 | "version" : "4.012" | |
564 | }, | |
565 | { | |
566 | "class" : "Pod::Weaver::Section::GenerateSection", | |
567 | "name" : "@DROLSKY/generate SUPPORT", | |
568 | "version" : "1.01" | |
569 | }, | |
570 | { | |
571 | "class" : "Pod::Weaver::Section::AllowOverride", | |
572 | "name" : "@DROLSKY/allow override SUPPORT", | |
573 | "version" : "0.05" | |
574 | }, | |
575 | { | |
576 | "class" : "Pod::Weaver::Section::GenerateSection", | |
577 | "name" : "@DROLSKY/generate DONATIONS", | |
578 | "version" : "1.01" | |
504 | 579 | }, |
505 | 580 | { |
506 | 581 | "class" : "Pod::Weaver::Section::Authors", |
507 | "name" : "Authors", | |
582 | "name" : "@DROLSKY/Authors", | |
508 | 583 | "version" : "4.012" |
509 | 584 | }, |
510 | 585 | { |
511 | 586 | "class" : "Pod::Weaver::Section::Contributors", |
512 | "name" : "Contributors", | |
587 | "name" : "@DROLSKY/Contributors", | |
513 | 588 | "version" : "0.009" |
514 | 589 | }, |
515 | 590 | { |
516 | 591 | "class" : "Pod::Weaver::Section::Legal", |
517 | "name" : "Legal", | |
592 | "name" : "@DROLSKY/Legal", | |
593 | "version" : "4.012" | |
594 | }, | |
595 | { | |
596 | "class" : "Pod::Weaver::Section::Region", | |
597 | "name" : "@DROLSKY/footer", | |
518 | 598 | "version" : "4.012" |
519 | 599 | } |
520 | 600 | ] |
522 | 602 | }, |
523 | 603 | "name" : "@DROLSKY/SurgicalPodWeaver", |
524 | 604 | "version" : "0.0023" |
605 | }, | |
606 | { | |
607 | "class" : "Dist::Zilla::Plugin::ReadmeAnyFromPod", | |
608 | "config" : { | |
609 | "Dist::Zilla::Role::FileWatcher" : { | |
610 | "version" : "0.006" | |
611 | } | |
612 | }, | |
613 | "name" : "@DROLSKY/README.md in build", | |
614 | "version" : "0.160630" | |
525 | 615 | }, |
526 | 616 | { |
527 | 617 | "class" : "Dist::Zilla::Plugin::MojibakeTests", |
620 | 710 | "LICENSE", |
621 | 711 | "Makefile.PL", |
622 | 712 | "README.md", |
623 | "cpanfile" | |
713 | "cpanfile", | |
714 | "ppport.h" | |
624 | 715 | ], |
625 | 716 | "allow_dirty_match" : [], |
626 | 717 | "changelog" : "Changes" |
647 | 738 | "LICENSE", |
648 | 739 | "Makefile.PL", |
649 | 740 | "README.md", |
650 | "cpanfile" | |
741 | "cpanfile", | |
742 | "ppport.h" | |
651 | 743 | ], |
652 | 744 | "allow_dirty_match" : [], |
653 | 745 | "changelog" : "Changes" |
669 | 761 | "branch" : null, |
670 | 762 | "changelog" : "Changes", |
671 | 763 | "signed" : 0, |
672 | "tag" : "v1.22", | |
764 | "tag" : "v1.23", | |
673 | 765 | "tag_format" : "v%v", |
674 | 766 | "tag_message" : "v%v" |
675 | 767 | }, |
712 | 804 | } |
713 | 805 | }, |
714 | 806 | "name" : "@DROLSKY/BumpVersionAfterRelease", |
715 | "version" : "0.013" | |
807 | "version" : "0.015" | |
716 | 808 | }, |
717 | 809 | { |
718 | 810 | "class" : "Dist::Zilla::Plugin::Git::Commit", |
791 | 883 | { |
792 | 884 | "class" : "Dist::Zilla::Plugin::PurePerlTests", |
793 | 885 | "name" : "PurePerlTests", |
794 | "version" : "0.05" | |
886 | "version" : "0.06" | |
795 | 887 | }, |
796 | 888 | { |
797 | 889 | "class" : "Dist::Zilla::Plugin::FinderCode", |
863 | 955 | "J.R. Mash <jmash.code@gmail.com>", |
864 | 956 | "Noel Maddy <zhtwnpanta@gmail.com>", |
865 | 957 | "Olivier Mengué <dolmen@cpan.org>", |
958 | "Tony Cook <tony@develop-help.com>", | |
866 | 959 | "Vincent Pit <perl@profvince.com>" |
867 | 960 | ] |
868 | 961 | } |
28 | 28 | provides: |
29 | 29 | Params::Validate: |
30 | 30 | file: lib/Params/Validate.pm |
31 | version: '1.22' | |
31 | version: '1.23' | |
32 | 32 | Params::Validate::Constants: |
33 | 33 | file: lib/Params/Validate/Constants.pm |
34 | version: '1.22' | |
34 | version: '1.23' | |
35 | 35 | Params::Validate::PP: |
36 | 36 | file: lib/Params/Validate/PP.pm |
37 | version: '1.22' | |
37 | version: '1.23' | |
38 | 38 | Params::Validate::XS: |
39 | 39 | file: lib/Params/Validate/XS.pm |
40 | version: '1.22' | |
40 | version: '1.23' | |
41 | 41 | requires: |
42 | 42 | Carp: '0' |
43 | 43 | Exporter: '0' |
44 | JSON::PP: '2.27300' | |
45 | 44 | Module::Implementation: '0' |
46 | 45 | Scalar::Util: '1.10' |
47 | 46 | XSLoader: '0' |
53 | 52 | bugtracker: http://rt.cpan.org/Public/Dist/Display.html?Name=Params-Validate |
54 | 53 | homepage: http://metacpan.org/release/Params-Validate |
55 | 54 | repository: git://github.com/autarch/Params-Validate.git |
56 | version: '1.22' | |
55 | version: '1.23' | |
57 | 56 | x_Dist_Zilla: |
58 | 57 | perl: |
59 | 58 | version: '5.022001' |
76 | 75 | Dist::Zilla::Plugin::GatherDir: |
77 | 76 | exclude_filename: |
78 | 77 | - Build.PL |
78 | - CONTRIBUTING.md | |
79 | 79 | - LICENSE |
80 | 80 | - Makefile.PL |
81 | 81 | - README.md |
82 | 82 | - cpanfile |
83 | - ppport.h | |
83 | 84 | exclude_match: [] |
84 | 85 | follow_symlinks: 0 |
85 | 86 | include_dotfiles: 0 |
149 | 150 | modules: [] |
150 | 151 | phase: release |
151 | 152 | skip: |
153 | - Dist::Zilla::Plugin::DROLSKY::CheckChangesHasContent | |
152 | 154 | - Dist::Zilla::Plugin::DROLSKY::Contributors |
155 | - Dist::Zilla::Plugin::DROLSKY::Git::CheckFor::CorrectBranch | |
153 | 156 | - Dist::Zilla::Plugin::DROLSKY::License |
154 | 157 | - Dist::Zilla::Plugin::DROLSKY::TidyAll |
155 | 158 | - Dist::Zilla::Plugin::DROLSKY::VersionProvider |
156 | 159 | name: '@DROLSKY/PromptIfStale' |
157 | 160 | version: '0.047' |
158 | - | |
159 | class: Dist::Zilla::Plugin::ReadmeAnyFromPod | |
160 | config: | |
161 | Dist::Zilla::Role::FileWatcher: | |
162 | version: '0.006' | |
163 | name: '@DROLSKY/README.md in build' | |
164 | version: '0.150250' | |
165 | - | |
166 | class: Dist::Zilla::Plugin::ReadmeAnyFromPod | |
167 | config: | |
168 | Dist::Zilla::Role::FileWatcher: | |
169 | version: '0.006' | |
170 | name: '@DROLSKY/README.md in root' | |
171 | version: '0.150250' | |
172 | 161 | - |
173 | 162 | class: Dist::Zilla::Plugin::Test::Pod::Coverage::Configurable |
174 | 163 | name: '@DROLSKY/Test::Pod::Coverage::Configurable' |
193 | 182 | - SCALARREF |
194 | 183 | - ValidatePos |
195 | 184 | - baz |
185 | - drolsky | |
196 | 186 | - onwards |
197 | 187 | - pre |
198 | 188 | - runtime |
202 | 192 | - |
203 | 193 | class: Dist::Zilla::Plugin::Test::ReportPrereqs |
204 | 194 | name: '@DROLSKY/Test::ReportPrereqs' |
205 | version: '0.021' | |
195 | version: '0.024' | |
206 | 196 | - |
207 | 197 | class: Dist::Zilla::Plugin::ManifestSkip |
208 | 198 | name: '@DROLSKY/ManifestSkip' |
248 | 238 | name: '@DROLSKY/UploadToCPAN' |
249 | 239 | version: '5.043' |
250 | 240 | - |
241 | class: Dist::Zilla::Plugin::GenerateFile::FromShareDir | |
242 | config: | |
243 | Dist::Zilla::Plugin::GenerateFile::FromShareDir: | |
244 | destination_filename: CONTRIBUTING.md | |
245 | dist: Dist-Zilla-PluginBundle-DROLSKY | |
246 | encoding: UTF-8 | |
247 | has_xs: '' | |
248 | location: build | |
249 | source_filename: CONTRIBUTING.md | |
250 | Dist::Zilla::Role::RepoFileInjector: | |
251 | allow_overwrite: 1 | |
252 | repo_root: . | |
253 | version: '0.005' | |
254 | name: '@DROLSKY/generate CONTRIBUTING' | |
255 | version: '0.009' | |
256 | - | |
251 | 257 | class: Dist::Zilla::Plugin::CheckPrereqsIndexed |
252 | 258 | name: '@DROLSKY/CheckPrereqsIndexed' |
253 | 259 | version: '0.017' |
256 | 262 | name: '@DROLSKY/CPANFile' |
257 | 263 | version: '5.043' |
258 | 264 | - |
265 | class: Dist::Zilla::Plugin::DROLSKY::CheckChangesHasContent | |
266 | name: '@DROLSKY/DROLSKY::CheckChangesHasContent' | |
267 | version: '0.45' | |
268 | - | |
259 | 269 | class: Dist::Zilla::Plugin::DROLSKY::Contributors |
260 | 270 | name: '@DROLSKY/DROLSKY::Contributors' |
261 | version: '0.42' | |
271 | version: '0.45' | |
262 | 272 | - |
263 | 273 | class: Dist::Zilla::Plugin::DROLSKY::License |
264 | 274 | name: '@DROLSKY/DROLSKY::License' |
265 | version: '0.42' | |
275 | version: '0.45' | |
266 | 276 | - |
267 | 277 | class: Dist::Zilla::Plugin::DROLSKY::TidyAll |
268 | 278 | name: '@DROLSKY/DROLSKY::TidyAll' |
269 | version: '0.42' | |
279 | version: '0.45' | |
270 | 280 | - |
271 | 281 | class: Dist::Zilla::Plugin::DROLSKY::VersionProvider |
272 | 282 | name: '@DROLSKY/DROLSKY::VersionProvider' |
273 | version: '0.42' | |
283 | version: '0.45' | |
274 | 284 | - |
275 | 285 | class: Dist::Zilla::Plugin::DROLSKY::Git::CheckFor::CorrectBranch |
276 | 286 | config: |
277 | 287 | Dist::Zilla::Role::Git::Repo: |
278 | 288 | repo_root: . |
279 | 289 | name: '@DROLSKY/DROLSKY::Git::CheckFor::CorrectBranch' |
280 | version: '0.42' | |
290 | version: '0.45' | |
281 | 291 | - |
282 | 292 | class: Dist::Zilla::Plugin::Git::CheckFor::MergeConflicts |
283 | 293 | config: |
295 | 305 | paths: |
296 | 306 | - . |
297 | 307 | name: '@DROLSKY/Git::Contributors' |
298 | version: '0.018' | |
308 | version: '0.020' | |
299 | 309 | - |
300 | 310 | class: Dist::Zilla::Plugin::InstallGuide |
301 | 311 | name: '@DROLSKY/InstallGuide' |
303 | 313 | - |
304 | 314 | class: Dist::Zilla::Plugin::Meta::Contributors |
305 | 315 | name: '@DROLSKY/Meta::Contributors' |
306 | version: '0.002' | |
316 | version: '0.003' | |
307 | 317 | - |
308 | 318 | class: Dist::Zilla::Plugin::MetaConfig |
309 | 319 | name: '@DROLSKY/MetaConfig' |
316 | 326 | class: Dist::Zilla::Plugin::SurgicalPodWeaver |
317 | 327 | config: |
318 | 328 | Dist::Zilla::Plugin::PodWeaver: |
329 | config_plugins: | |
330 | - '@DROLSKY' | |
319 | 331 | finder: |
320 | 332 | - ':InstallModules' |
321 | 333 | - ':ExecFiles' |
329 | 341 | name: '@CorePrep/H1Nester' |
330 | 342 | version: '4.012' |
331 | 343 | - |
344 | class: Pod::Weaver::Plugin::SingleEncoding | |
345 | name: '@DROLSKY/SingleEncoding' | |
346 | version: '4.012' | |
347 | - | |
348 | class: Pod::Weaver::Plugin::Transformer | |
349 | name: '@DROLSKY/List' | |
350 | version: '4.012' | |
351 | - | |
352 | class: Pod::Weaver::Plugin::Transformer | |
353 | name: '@DROLSKY/Verbatim' | |
354 | version: '4.012' | |
355 | - | |
356 | class: Pod::Weaver::Section::Region | |
357 | name: '@DROLSKY/header' | |
358 | version: '4.012' | |
359 | - | |
332 | 360 | class: Pod::Weaver::Section::Name |
333 | name: Name | |
361 | name: '@DROLSKY/Name' | |
334 | 362 | version: '4.012' |
335 | 363 | - |
336 | 364 | class: Pod::Weaver::Section::Version |
337 | name: Version | |
365 | name: '@DROLSKY/Version' | |
338 | 366 | version: '4.012' |
339 | 367 | - |
340 | 368 | class: Pod::Weaver::Section::Region |
341 | name: prelude | |
369 | name: '@DROLSKY/prelude' | |
342 | 370 | version: '4.012' |
343 | 371 | - |
344 | 372 | class: Pod::Weaver::Section::Generic |
349 | 377 | name: DESCRIPTION |
350 | 378 | version: '4.012' |
351 | 379 | - |
380 | class: Pod::Weaver::Section::Generic | |
381 | name: OVERVIEW | |
382 | version: '4.012' | |
383 | - | |
384 | class: Pod::Weaver::Section::Collect | |
385 | name: ATTRIBUTES | |
386 | version: '4.012' | |
387 | - | |
388 | class: Pod::Weaver::Section::Collect | |
389 | name: METHODS | |
390 | version: '4.012' | |
391 | - | |
392 | class: Pod::Weaver::Section::Collect | |
393 | name: FUNCTIONS | |
394 | version: '4.012' | |
395 | - | |
396 | class: Pod::Weaver::Section::Collect | |
397 | name: TYPES | |
398 | version: '4.012' | |
399 | - | |
352 | 400 | class: Pod::Weaver::Section::Leftovers |
353 | name: Leftovers | |
401 | name: '@DROLSKY/Leftovers' | |
354 | 402 | version: '4.012' |
355 | 403 | - |
356 | 404 | class: Pod::Weaver::Section::Region |
357 | name: postlude | |
358 | version: '4.012' | |
405 | name: '@DROLSKY/postlude' | |
406 | version: '4.012' | |
407 | - | |
408 | class: Pod::Weaver::Section::GenerateSection | |
409 | name: '@DROLSKY/generate SUPPORT' | |
410 | version: '1.01' | |
411 | - | |
412 | class: Pod::Weaver::Section::AllowOverride | |
413 | name: '@DROLSKY/allow override SUPPORT' | |
414 | version: '0.05' | |
415 | - | |
416 | class: Pod::Weaver::Section::GenerateSection | |
417 | name: '@DROLSKY/generate DONATIONS' | |
418 | version: '1.01' | |
359 | 419 | - |
360 | 420 | class: Pod::Weaver::Section::Authors |
361 | name: Authors | |
421 | name: '@DROLSKY/Authors' | |
362 | 422 | version: '4.012' |
363 | 423 | - |
364 | 424 | class: Pod::Weaver::Section::Contributors |
365 | name: Contributors | |
425 | name: '@DROLSKY/Contributors' | |
366 | 426 | version: '0.009' |
367 | 427 | - |
368 | 428 | class: Pod::Weaver::Section::Legal |
369 | name: Legal | |
429 | name: '@DROLSKY/Legal' | |
430 | version: '4.012' | |
431 | - | |
432 | class: Pod::Weaver::Section::Region | |
433 | name: '@DROLSKY/footer' | |
370 | 434 | version: '4.012' |
371 | 435 | name: '@DROLSKY/SurgicalPodWeaver' |
372 | 436 | version: '0.0023' |
437 | - | |
438 | class: Dist::Zilla::Plugin::ReadmeAnyFromPod | |
439 | config: | |
440 | Dist::Zilla::Role::FileWatcher: | |
441 | version: '0.006' | |
442 | name: '@DROLSKY/README.md in build' | |
443 | version: '0.160630' | |
373 | 444 | - |
374 | 445 | class: Dist::Zilla::Plugin::MojibakeTests |
375 | 446 | name: '@DROLSKY/MojibakeTests' |
448 | 519 | - Makefile.PL |
449 | 520 | - README.md |
450 | 521 | - cpanfile |
522 | - ppport.h | |
451 | 523 | allow_dirty_match: [] |
452 | 524 | changelog: Changes |
453 | 525 | Dist::Zilla::Role::Git::Repo: |
469 | 541 | - Makefile.PL |
470 | 542 | - README.md |
471 | 543 | - cpanfile |
544 | - ppport.h | |
472 | 545 | allow_dirty_match: [] |
473 | 546 | changelog: Changes |
474 | 547 | Dist::Zilla::Role::Git::Repo: |
484 | 557 | branch: ~ |
485 | 558 | changelog: Changes |
486 | 559 | signed: 0 |
487 | tag: v1.22 | |
560 | tag: v1.23 | |
488 | 561 | tag_format: v%v |
489 | 562 | tag_message: v%v |
490 | 563 | Dist::Zilla::Role::Git::Repo: |
514 | 587 | global: 0 |
515 | 588 | munge_makefile_pl: 1 |
516 | 589 | name: '@DROLSKY/BumpVersionAfterRelease' |
517 | version: '0.013' | |
590 | version: '0.015' | |
518 | 591 | - |
519 | 592 | class: Dist::Zilla::Plugin::Git::Commit |
520 | 593 | config: |
571 | 644 | - |
572 | 645 | class: Dist::Zilla::Plugin::PurePerlTests |
573 | 646 | name: PurePerlTests |
574 | version: '0.05' | |
647 | version: '0.06' | |
575 | 648 | - |
576 | 649 | class: Dist::Zilla::Plugin::FinderCode |
577 | 650 | name: ':InstallModules' |
627 | 700 | - 'J.R. Mash <jmash.code@gmail.com>' |
628 | 701 | - 'Noel Maddy <zhtwnpanta@gmail.com>' |
629 | 702 | - 'Olivier Mengué <dolmen@cpan.org>' |
703 | - 'Tony Cook <tony@develop-help.com>' | |
630 | 704 | - 'Vincent Pit <perl@profvince.com>' |
0 | NAME | |
1 | ||
2 | Params::Validate - Validate method/function parameters | |
3 | ||
4 | VERSION | |
5 | ||
6 | version 1.22 | |
7 | ||
8 | SYNOPSIS | |
9 | ||
10 | use Params::Validate qw(:all); | |
11 | ||
12 | # takes named params (hash or hashref) | |
13 | sub foo { | |
14 | validate( | |
15 | @_, { | |
16 | foo => 1, # mandatory | |
17 | bar => 0, # optional | |
18 | } | |
19 | ); | |
20 | } | |
21 | ||
22 | # takes positional params | |
23 | sub bar { | |
24 | # first two are mandatory, third is optional | |
25 | validate_pos( @_, 1, 1, 0 ); | |
26 | } | |
27 | ||
28 | sub foo2 { | |
29 | validate( | |
30 | @_, { | |
31 | foo => | |
32 | # specify a type | |
33 | { type => ARRAYREF }, | |
34 | bar => | |
35 | # specify an interface | |
36 | { can => [ 'print', 'flush', 'frobnicate' ] }, | |
37 | baz => { | |
38 | type => SCALAR, # a scalar ... | |
39 | # ... that is a plain integer ... | |
40 | regex => qr/^\d+$/, | |
41 | callbacks => { # ... and smaller than 90 | |
42 | 'less than 90' => sub { shift() < 90 }, | |
43 | }, | |
44 | } | |
45 | } | |
46 | ); | |
47 | } | |
48 | ||
49 | sub callback_with_custom_error { | |
50 | validate( | |
51 | @_, | |
52 | { | |
53 | foo => callbacks => { | |
54 | 'is an integer' => sub { | |
55 | return 1 if $_[0] =~ /^-?[1-9][0-9]*$/; | |
56 | die "$_[0] is not a valid integer value"; | |
57 | }, | |
58 | } | |
59 | } | |
60 | ); | |
61 | } | |
62 | ||
63 | sub with_defaults { | |
64 | my %p = validate( | |
65 | @_, { | |
66 | # required | |
67 | foo => 1, | |
68 | # $p{bar} will be 99 if bar is not given. bar is now | |
69 | # optional. | |
70 | bar => { default => 99 } | |
71 | } | |
72 | ); | |
73 | } | |
74 | ||
75 | sub pos_with_defaults { | |
76 | my @p = validate_pos( @_, 1, { default => 99 } ); | |
77 | } | |
78 | ||
79 | sub sets_options_on_call { | |
80 | my %p = validate_with( | |
81 | params => \@_, | |
82 | spec => { foo => { type => SCALAR, default => 2 } }, | |
83 | normalize_keys => sub { $_[0] =~ s/^-//; lc $_[0] }, | |
84 | ); | |
85 | } | |
86 | ||
87 | DESCRIPTION | |
88 | ||
89 | The Params::Validate module allows you to validate method or function | |
90 | call parameters to an arbitrary level of specificity. At the simplest | |
91 | level, it is capable of validating the required parameters were given | |
92 | and that no unspecified additional parameters were passed in. | |
93 | ||
94 | It is also capable of determining that a parameter is of a specific | |
95 | type, that it is an object of a certain class hierarchy, that it | |
96 | possesses certain methods, or applying validation callbacks to | |
97 | arguments. | |
98 | ||
99 | EXPORT | |
100 | ||
101 | The module always exports the validate() and validate_pos() functions. | |
102 | ||
103 | It also has an additional function available for export, validate_with, | |
104 | which can be used to validate any type of parameters, and set various | |
105 | options on a per-invocation basis. | |
106 | ||
107 | In addition, it can export the following constants, which are used as | |
108 | part of the type checking. These are SCALAR, ARRAYREF, HASHREF, | |
109 | CODEREF, GLOB, GLOBREF, and SCALARREF, UNDEF, OBJECT, BOOLEAN, and | |
110 | HANDLE. These are explained in the section on Type Validation. | |
111 | ||
112 | The constants are available via the export tag :types. There is also an | |
113 | :all tag which includes all of the constants as well as the | |
114 | validation_options() function. | |
115 | ||
116 | PARAMETER VALIDATION | |
117 | ||
118 | The validation mechanisms provided by this module can handle both named | |
119 | or positional parameters. For the most part, the same features are | |
120 | available for each. The biggest difference is the way that the | |
121 | validation specification is given to the relevant subroutine. The other | |
122 | difference is in the error messages produced when validation checks | |
123 | fail. | |
124 | ||
125 | When handling named parameters, the module will accept either a hash or | |
126 | a hash reference. | |
127 | ||
128 | Subroutines expecting named parameters should call the validate() | |
129 | subroutine like this: | |
130 | ||
0 | # NAME | |
1 | ||
2 | Params::Validate - Validate method/function parameters | |
3 | ||
4 | # VERSION | |
5 | ||
6 | version 1.23 | |
7 | ||
8 | # SYNOPSIS | |
9 | ||
10 | use Params::Validate qw(:all); | |
11 | ||
12 | # takes named params (hash or hashref) | |
13 | sub foo { | |
131 | 14 | validate( |
132 | 15 | @_, { |
133 | parameter1 => validation spec, | |
134 | parameter2 => validation spec, | |
135 | ... | |
16 | foo => 1, # mandatory | |
17 | bar => 0, # optional | |
136 | 18 | } |
137 | 19 | ); |
138 | ||
139 | Subroutines expecting positional parameters should call the | |
140 | validate_pos() subroutine like this: | |
141 | ||
142 | validate_pos( @_, { validation spec }, { validation spec } ); | |
143 | ||
144 | Mandatory/Optional Parameters | |
145 | ||
146 | If you just want to specify that some parameters are mandatory and | |
147 | others are optional, this can be done very simply. | |
148 | ||
149 | For a subroutine expecting named parameters, you would do this: | |
150 | ||
151 | validate( @_, { foo => 1, bar => 1, baz => 0 } ); | |
152 | ||
153 | This says that the "foo" and "bar" parameters are mandatory and that | |
154 | the "baz" parameter is optional. The presence of any other parameters | |
155 | will cause an error. | |
156 | ||
157 | For a subroutine expecting positional parameters, you would do this: | |
158 | ||
159 | validate_pos( @_, 1, 1, 0, 0 ); | |
160 | ||
161 | This says that you expect at least 2 and no more than 4 parameters. If | |
162 | you have a subroutine that has a minimum number of parameters but can | |
163 | take any maximum number, you can do this: | |
164 | ||
165 | validate_pos( @_, 1, 1, (0) x (@_ - 2) ); | |
166 | ||
167 | This will always be valid as long as at least two parameters are given. | |
168 | A similar construct could be used for the more complex validation | |
169 | parameters described further on. | |
170 | ||
171 | Please note that this: | |
172 | ||
173 | validate_pos( @_, 1, 1, 0, 1, 1 ); | |
174 | ||
175 | makes absolutely no sense, so don't do it. Any zeros must come at the | |
176 | end of the validation specification. | |
177 | ||
178 | In addition, if you specify that a parameter can have a default, then | |
179 | it is considered optional. | |
180 | ||
181 | Type Validation | |
182 | ||
183 | This module supports the following simple types, which can be exported | |
184 | as constants: | |
185 | ||
186 | * SCALAR | |
187 | ||
188 | A scalar which is not a reference, such as 10 or 'hello'. A parameter | |
189 | that is undefined is not treated as a scalar. If you want to allow | |
190 | undefined values, you will have to specify SCALAR | UNDEF. | |
191 | ||
192 | * ARRAYREF | |
193 | ||
194 | An array reference such as [1, 2, 3] or \@foo. | |
195 | ||
196 | * HASHREF | |
197 | ||
198 | A hash reference such as { a => 1, b => 2 } or \%bar. | |
199 | ||
200 | * CODEREF | |
201 | ||
202 | A subroutine reference such as \&foo_sub or sub { print "hello" }. | |
203 | ||
204 | * GLOB | |
205 | ||
206 | This one is a bit tricky. A glob would be something like *FOO, but | |
207 | not \*FOO, which is a glob reference. It should be noted that this | |
208 | trick: | |
209 | ||
210 | my $fh = do { local *FH; }; | |
211 | ||
212 | makes $fh a glob, not a glob reference. On the other hand, the return | |
213 | value from Symbol::gensym is a glob reference. Either can be used as | |
214 | a file or directory handle. | |
215 | ||
216 | * GLOBREF | |
217 | ||
218 | A glob reference such as \*FOO. See the GLOB entry above for more | |
219 | details. | |
220 | ||
221 | * SCALARREF | |
222 | ||
223 | A reference to a scalar such as \$x. | |
224 | ||
225 | * UNDEF | |
226 | ||
227 | An undefined value | |
228 | ||
229 | * OBJECT | |
230 | ||
231 | A blessed reference. | |
232 | ||
233 | * BOOLEAN | |
234 | ||
235 | This is a special option, and is just a shortcut for UNDEF | SCALAR. | |
236 | ||
237 | * HANDLE | |
238 | ||
239 | This option is also special, and is just a shortcut for GLOB | | |
240 | GLOBREF. However, it seems likely that most people interested in | |
241 | either globs or glob references are likely to really be interested in | |
242 | whether the parameter in question could be a valid file or directory | |
243 | handle. | |
244 | ||
245 | To specify that a parameter must be of a given type when using named | |
246 | parameters, do this: | |
247 | ||
248 | validate( | |
249 | @_, { | |
250 | foo => { type => SCALAR }, | |
251 | bar => { type => HASHREF } | |
252 | } | |
253 | ); | |
254 | ||
255 | If a parameter can be of more than one type, just use the bitwise or | |
256 | (|) operator to combine them. | |
257 | ||
258 | validate( @_, { foo => { type => GLOB | GLOBREF } ); | |
259 | ||
260 | For positional parameters, this can be specified as follows: | |
261 | ||
262 | validate_pos( @_, { type => SCALAR | ARRAYREF }, { type => CODEREF } ); | |
263 | ||
264 | Interface Validation | |
265 | ||
266 | To specify that a parameter is expected to have a certain set of | |
267 | methods, we can do the following: | |
268 | ||
20 | } | |
21 | ||
22 | # takes positional params | |
23 | sub bar { | |
24 | # first two are mandatory, third is optional | |
25 | validate_pos( @_, 1, 1, 0 ); | |
26 | } | |
27 | ||
28 | sub foo2 { | |
269 | 29 | validate( |
270 | 30 | @_, { |
271 | 31 | foo => |
272 | # just has to be able to ->bar | |
273 | { can => 'bar' } | |
32 | # specify a type | |
33 | { type => ARRAYREF }, | |
34 | bar => | |
35 | # specify an interface | |
36 | { can => [ 'print', 'flush', 'frobnicate' ] }, | |
37 | baz => { | |
38 | type => SCALAR, # a scalar ... | |
39 | # ... that is a plain integer ... | |
40 | regex => qr/^\d+$/, | |
41 | callbacks => { # ... and smaller than 90 | |
42 | 'less than 90' => sub { shift() < 90 }, | |
43 | }, | |
44 | } | |
274 | 45 | } |
275 | 46 | ); |
276 | ||
277 | ... or ... | |
278 | ||
279 | validate( | |
280 | @_, { | |
281 | foo => | |
282 | # must be able to ->bar and ->print | |
283 | { can => [qw( bar print )] } | |
284 | } | |
285 | ); | |
286 | ||
287 | Class Validation | |
288 | ||
289 | A word of warning. When constructing your external interfaces, it is | |
290 | probably better to specify what methods you expect an object to have | |
291 | rather than what class it should be of (or a child of). This will make | |
292 | your API much more flexible. | |
293 | ||
294 | With that said, if you want to validate that an incoming parameter | |
295 | belongs to a class (or child class) or classes, do: | |
296 | ||
297 | validate( | |
298 | @_, | |
299 | { foo => { isa => 'My::Frobnicator' } } | |
300 | ); | |
301 | ||
302 | ... or ... | |
303 | ||
304 | validate( | |
305 | @_, | |
306 | # must be both, not either! | |
307 | { foo => { isa => [qw( My::Frobnicator IO::Handle )] } } | |
308 | ); | |
309 | ||
310 | Regex Validation | |
311 | ||
312 | If you want to specify that a given parameter must match a specific | |
313 | regular expression, this can be done with "regex" spec key. For | |
314 | example: | |
315 | ||
316 | validate( | |
317 | @_, | |
318 | { foo => { regex => qr/^\d+$/ } } | |
319 | ); | |
320 | ||
321 | The value of the "regex" key may be either a string or a pre-compiled | |
322 | regex created via qr. | |
323 | ||
324 | If the value being checked against a regex is undefined, the regex is | |
325 | explicitly checked against the empty string ('') instead, in order to | |
326 | avoid "Use of uninitialized value" warnings. | |
327 | ||
328 | The Regexp::Common module on CPAN is an excellent source of regular | |
329 | expressions suitable for validating input. | |
330 | ||
331 | Callback Validation | |
332 | ||
333 | If none of the above are enough, it is possible to pass in one or more | |
334 | callbacks to validate the parameter. The callback will be given the | |
335 | value of the parameter as its first argument. Its second argument will | |
336 | be all the parameters, as a reference to either a hash or array. | |
337 | Callbacks are specified as hash reference. The key is an id for the | |
338 | callback (used in error messages) and the value is a subroutine | |
339 | reference, such as: | |
340 | ||
47 | } | |
48 | ||
49 | sub callback_with_custom_error { | |
341 | 50 | validate( |
342 | 51 | @_, |
343 | 52 | { |
344 | foo => { | |
345 | callbacks => { | |
346 | 'smaller than a breadbox' => sub { shift() < $breadbox }, | |
347 | 'green or blue' => sub { | |
348 | return 1 if $_[0] eq 'green' || $_[0] eq 'blue'; | |
349 | die "$_[0] is not green or blue!"; | |
350 | } | |
53 | foo => callbacks => { | |
54 | 'is an integer' => sub { | |
55 | return 1 if $_[0] =~ /^-?[1-9][0-9]*$/; | |
56 | die "$_[0] is not a valid integer value"; | |
57 | }, | |
58 | } | |
59 | } | |
60 | ); | |
61 | } | |
62 | ||
63 | sub with_defaults { | |
64 | my %p = validate( | |
65 | @_, { | |
66 | # required | |
67 | foo => 1, | |
68 | # $p{bar} will be 99 if bar is not given. bar is now | |
69 | # optional. | |
70 | bar => { default => 99 } | |
71 | } | |
72 | ); | |
73 | } | |
74 | ||
75 | sub pos_with_defaults { | |
76 | my @p = validate_pos( @_, 1, { default => 99 } ); | |
77 | } | |
78 | ||
79 | sub sets_options_on_call { | |
80 | my %p = validate_with( | |
81 | params => \@_, | |
82 | spec => { foo => { type => SCALAR, default => 2 } }, | |
83 | normalize_keys => sub { $_[0] =~ s/^-//; lc $_[0] }, | |
84 | ); | |
85 | } | |
86 | ||
87 | # DESCRIPTION | |
88 | ||
89 | The Params::Validate module allows you to validate method or function | |
90 | call parameters to an arbitrary level of specificity. At the simplest | |
91 | level, it is capable of validating the required parameters were given | |
92 | and that no unspecified additional parameters were passed in. | |
93 | ||
94 | It is also capable of determining that a parameter is of a specific | |
95 | type, that it is an object of a certain class hierarchy, that it | |
96 | possesses certain methods, or applying validation callbacks to | |
97 | arguments. | |
98 | ||
99 | ## EXPORT | |
100 | ||
101 | The module always exports the `validate()` and `validate_pos()` | |
102 | functions. | |
103 | ||
104 | It also has an additional function available for export, | |
105 | `validate_with`, which can be used to validate any type of | |
106 | parameters, and set various options on a per-invocation basis. | |
107 | ||
108 | In addition, it can export the following constants, which are used as | |
109 | part of the type checking. These are `SCALAR`, `ARRAYREF`, | |
110 | `HASHREF`, `CODEREF`, `GLOB`, `GLOBREF`, and `SCALARREF`, | |
111 | `UNDEF`, `OBJECT`, `BOOLEAN`, and `HANDLE`. These are explained | |
112 | in the section on [Type Validation](https://metacpan.org/pod/Params::Validate#Type-Validation). | |
113 | ||
114 | The constants are available via the export tag `:types`. There is | |
115 | also an `:all` tag which includes all of the constants as well as the | |
116 | `validation_options()` function. | |
117 | ||
118 | # PARAMETER VALIDATION | |
119 | ||
120 | The validation mechanisms provided by this module can handle both | |
121 | named or positional parameters. For the most part, the same features | |
122 | are available for each. The biggest difference is the way that the | |
123 | validation specification is given to the relevant subroutine. The | |
124 | other difference is in the error messages produced when validation | |
125 | checks fail. | |
126 | ||
127 | When handling named parameters, the module will accept either a hash | |
128 | or a hash reference. | |
129 | ||
130 | Subroutines expecting named parameters should call the `validate()` | |
131 | subroutine like this: | |
132 | ||
133 | validate( | |
134 | @_, { | |
135 | parameter1 => validation spec, | |
136 | parameter2 => validation spec, | |
137 | ... | |
138 | } | |
139 | ); | |
140 | ||
141 | Subroutines expecting positional parameters should call the | |
142 | `validate_pos()` subroutine like this: | |
143 | ||
144 | validate_pos( @_, { validation spec }, { validation spec } ); | |
145 | ||
146 | ## Mandatory/Optional Parameters | |
147 | ||
148 | If you just want to specify that some parameters are mandatory and | |
149 | others are optional, this can be done very simply. | |
150 | ||
151 | For a subroutine expecting named parameters, you would do this: | |
152 | ||
153 | validate( @_, { foo => 1, bar => 1, baz => 0 } ); | |
154 | ||
155 | This says that the "foo" and "bar" parameters are mandatory and that | |
156 | the "baz" parameter is optional. The presence of any other | |
157 | parameters will cause an error. | |
158 | ||
159 | For a subroutine expecting positional parameters, you would do this: | |
160 | ||
161 | validate_pos( @_, 1, 1, 0, 0 ); | |
162 | ||
163 | This says that you expect at least 2 and no more than 4 parameters. | |
164 | If you have a subroutine that has a minimum number of parameters but | |
165 | can take any maximum number, you can do this: | |
166 | ||
167 | validate_pos( @_, 1, 1, (0) x (@_ - 2) ); | |
168 | ||
169 | This will always be valid as long as at least two parameters are | |
170 | given. A similar construct could be used for the more complex | |
171 | validation parameters described further on. | |
172 | ||
173 | Please note that this: | |
174 | ||
175 | validate_pos( @_, 1, 1, 0, 1, 1 ); | |
176 | ||
177 | makes absolutely no sense, so don't do it. Any zeros must come at the | |
178 | end of the validation specification. | |
179 | ||
180 | In addition, if you specify that a parameter can have a default, then | |
181 | it is considered optional. | |
182 | ||
183 | ## Type Validation | |
184 | ||
185 | This module supports the following simple types, which can be | |
186 | [exported as constants](#export): | |
187 | ||
188 | - SCALAR | |
189 | ||
190 | A scalar which is not a reference, such as `10` or `'hello'`. A | |
191 | parameter that is undefined is **not** treated as a scalar. If you | |
192 | want to allow undefined values, you will have to specify `SCALAR | | |
193 | UNDEF`. | |
194 | ||
195 | - ARRAYREF | |
196 | ||
197 | An array reference such as `[1, 2, 3]` or `\@foo`. | |
198 | ||
199 | - HASHREF | |
200 | ||
201 | A hash reference such as `{ a => 1, b => 2 }` or `\%bar`. | |
202 | ||
203 | - CODEREF | |
204 | ||
205 | A subroutine reference such as `\&foo_sub` or `sub { print "hello" }`. | |
206 | ||
207 | - GLOB | |
208 | ||
209 | This one is a bit tricky. A glob would be something like `*FOO`, but | |
210 | not `\*FOO`, which is a glob reference. It should be noted that this | |
211 | trick: | |
212 | ||
213 | my $fh = do { local *FH; }; | |
214 | ||
215 | makes `$fh` a glob, not a glob reference. On the other hand, the | |
216 | return value from `Symbol::gensym` is a glob reference. Either can | |
217 | be used as a file or directory handle. | |
218 | ||
219 | - GLOBREF | |
220 | ||
221 | A glob reference such as `\*FOO`. See the [GLOB](https://metacpan.org/pod/GLOB) entry above | |
222 | for more details. | |
223 | ||
224 | - SCALARREF | |
225 | ||
226 | A reference to a scalar such as `\$x`. | |
227 | ||
228 | - UNDEF | |
229 | ||
230 | An undefined value | |
231 | ||
232 | - OBJECT | |
233 | ||
234 | A blessed reference. | |
235 | ||
236 | - BOOLEAN | |
237 | ||
238 | This is a special option, and is just a shortcut for `UNDEF | SCALAR`. | |
239 | ||
240 | - HANDLE | |
241 | ||
242 | This option is also special, and is just a shortcut for `GLOB | | |
243 | GLOBREF`. However, it seems likely that most people interested in | |
244 | either globs or glob references are likely to really be interested in | |
245 | whether the parameter in question could be a valid file or directory | |
246 | handle. | |
247 | ||
248 | To specify that a parameter must be of a given type when using named | |
249 | parameters, do this: | |
250 | ||
251 | validate( | |
252 | @_, { | |
253 | foo => { type => SCALAR }, | |
254 | bar => { type => HASHREF } | |
255 | } | |
256 | ); | |
257 | ||
258 | If a parameter can be of more than one type, just use the bitwise or | |
259 | (`|`) operator to combine them. | |
260 | ||
261 | validate( @_, { foo => { type => GLOB | GLOBREF } ); | |
262 | ||
263 | For positional parameters, this can be specified as follows: | |
264 | ||
265 | validate_pos( @_, { type => SCALAR | ARRAYREF }, { type => CODEREF } ); | |
266 | ||
267 | ## Interface Validation | |
268 | ||
269 | To specify that a parameter is expected to have a certain set of | |
270 | methods, we can do the following: | |
271 | ||
272 | validate( | |
273 | @_, { | |
274 | foo => | |
275 | # just has to be able to ->bar | |
276 | { can => 'bar' } | |
277 | } | |
278 | ); | |
279 | ||
280 | ... or ... | |
281 | ||
282 | validate( | |
283 | @_, { | |
284 | foo => | |
285 | # must be able to ->bar and ->print | |
286 | { can => [qw( bar print )] } | |
287 | } | |
288 | ); | |
289 | ||
290 | ## Class Validation | |
291 | ||
292 | A word of warning. When constructing your external interfaces, it is | |
293 | probably better to specify what methods you expect an object to | |
294 | have rather than what class it should be of (or a child of). This | |
295 | will make your API much more flexible. | |
296 | ||
297 | With that said, if you want to validate that an incoming parameter | |
298 | belongs to a class (or child class) or classes, do: | |
299 | ||
300 | validate( | |
301 | @_, | |
302 | { foo => { isa => 'My::Frobnicator' } } | |
303 | ); | |
304 | ||
305 | ... or ... | |
306 | ||
307 | validate( | |
308 | @_, | |
309 | # must be both, not either! | |
310 | { foo => { isa => [qw( My::Frobnicator IO::Handle )] } } | |
311 | ); | |
312 | ||
313 | ## Regex Validation | |
314 | ||
315 | If you want to specify that a given parameter must match a specific | |
316 | regular expression, this can be done with "regex" spec key. For | |
317 | example: | |
318 | ||
319 | validate( | |
320 | @_, | |
321 | { foo => { regex => qr/^\d+$/ } } | |
322 | ); | |
323 | ||
324 | The value of the "regex" key may be either a string or a pre-compiled | |
325 | regex created via `qr`. | |
326 | ||
327 | If the value being checked against a regex is undefined, the regex is | |
328 | explicitly checked against the empty string ('') instead, in order to | |
329 | avoid "Use of uninitialized value" warnings. | |
330 | ||
331 | The `Regexp::Common` module on CPAN is an excellent source of regular | |
332 | expressions suitable for validating input. | |
333 | ||
334 | ## Callback Validation | |
335 | ||
336 | If none of the above are enough, it is possible to pass in one or more | |
337 | callbacks to validate the parameter. The callback will be given the | |
338 | **value** of the parameter as its first argument. Its second argument | |
339 | will be all the parameters, as a reference to either a hash or array. | |
340 | Callbacks are specified as hash reference. The key is an id for the | |
341 | callback (used in error messages) and the value is a subroutine | |
342 | reference, such as: | |
343 | ||
344 | validate( | |
345 | @_, | |
346 | { | |
347 | foo => { | |
348 | callbacks => { | |
349 | 'smaller than a breadbox' => sub { shift() < $breadbox }, | |
350 | 'green or blue' => sub { | |
351 | return 1 if $_[0] eq 'green' || $_[0] eq 'blue'; | |
352 | die "$_[0] is not green or blue!"; | |
351 | 353 | } |
352 | 354 | } |
353 | 355 | } |
354 | ); | |
355 | ||
356 | validate( | |
357 | @_, { | |
358 | foo => { | |
359 | callbacks => { | |
360 | 'bigger than baz' => sub { $_[0] > $_[1]->{baz} } | |
361 | } | |
356 | } | |
357 | ); | |
358 | ||
359 | validate( | |
360 | @_, { | |
361 | foo => { | |
362 | callbacks => { | |
363 | 'bigger than baz' => sub { $_[0] > $_[1]->{baz} } | |
362 | 364 | } |
363 | 365 | } |
364 | ); | |
365 | ||
366 | The callback should return a true value if the value is valid. If not, | |
367 | it can return false or die. If you return false, a generic error | |
368 | message will be thrown by Params::Validate. | |
369 | ||
370 | If your callback dies instead you can provide a custom error message. | |
371 | If the callback dies with a plain string, this string will be appended | |
372 | to an exception message generated by Params::Validate. If the callback | |
373 | dies with a reference (blessed or not), then this will be rethrown | |
374 | as-is by Params::Validate. | |
375 | ||
376 | Untainting | |
377 | ||
378 | If you want values untainted, set the "untaint" key in a spec hashref | |
379 | to a true value, like this: | |
380 | ||
381 | my %p = validate( | |
366 | } | |
367 | ); | |
368 | ||
369 | The callback should return a true value if the value is valid. If not, it can | |
370 | return false or die. If you return false, a generic error message will be | |
371 | thrown by `Params::Validate`. | |
372 | ||
373 | If your callback dies instead you can provide a custom error message. If the | |
374 | callback dies with a plain string, this string will be appended to an | |
375 | exception message generated by `Params::Validate`. If the callback dies with | |
376 | a reference (blessed or not), then this will be rethrown as-is by | |
377 | `Params::Validate`. | |
378 | ||
379 | ## Untainting | |
380 | ||
381 | If you want values untainted, set the "untaint" key in a spec hashref | |
382 | to a true value, like this: | |
383 | ||
384 | my %p = validate( | |
385 | @_, { | |
386 | foo => { type => SCALAR, untaint => 1 }, | |
387 | bar => { type => ARRAYREF } | |
388 | } | |
389 | ); | |
390 | ||
391 | This will untaint the "foo" parameter if the parameters are valid. | |
392 | ||
393 | Note that untainting is only done if _all parameters_ are valid. | |
394 | Also, only the return values are untainted, not the original values | |
395 | passed into the validation function. | |
396 | ||
397 | Asking for untainting of a reference value will not do anything, as | |
398 | `Params::Validate` will only attempt to untaint the reference itself. | |
399 | ||
400 | ## Mandatory/Optional Revisited | |
401 | ||
402 | If you want to specify something such as type or interface, plus the | |
403 | fact that a parameter can be optional, do this: | |
404 | ||
405 | validate( | |
406 | @_, { | |
407 | foo => { type => SCALAR }, | |
408 | bar => { type => ARRAYREF, optional => 1 } | |
409 | } | |
410 | ); | |
411 | ||
412 | or this for positional parameters: | |
413 | ||
414 | validate_pos( | |
415 | @_, | |
416 | { type => SCALAR }, | |
417 | { type => ARRAYREF, optional => 1 } | |
418 | ); | |
419 | ||
420 | By default, parameters are assumed to be mandatory unless specified as | |
421 | optional. | |
422 | ||
423 | ## Dependencies | |
424 | ||
425 | It also possible to specify that a given optional parameter depends on | |
426 | the presence of one or more other optional parameters. | |
427 | ||
428 | validate( | |
429 | @_, { | |
430 | cc_number => { | |
431 | type => SCALAR, | |
432 | optional => 1, | |
433 | depends => [ 'cc_expiration', 'cc_holder_name' ], | |
434 | }, | |
435 | cc_expiration => { type => SCALAR, optional => 1 }, | |
436 | cc_holder_name => { type => SCALAR, optional => 1 }, | |
437 | } | |
438 | ); | |
439 | ||
440 | In this case, "cc\_number", "cc\_expiration", and "cc\_holder\_name" are | |
441 | all optional. However, if "cc\_number" is provided, then | |
442 | "cc\_expiration" and "cc\_holder\_name" must be provided as well. | |
443 | ||
444 | This allows you to group together sets of parameters that all must be | |
445 | provided together. | |
446 | ||
447 | The `validate_pos()` version of dependencies is slightly different, | |
448 | in that you can only depend on one other parameter. Also, if for | |
449 | example, the second parameter 2 depends on the fourth parameter, then | |
450 | it implies a dependency on the third parameter as well. This is | |
451 | because if the fourth parameter is required, then the user must also | |
452 | provide a third parameter so that there can be four parameters in | |
453 | total. | |
454 | ||
455 | `Params::Validate` will die if you try to depend on a parameter not | |
456 | declared as part of your parameter specification. | |
457 | ||
458 | ## Specifying defaults | |
459 | ||
460 | If the `validate()` or `validate_pos()` functions are called in a list | |
461 | context, they will return a hash or containing the original parameters plus | |
462 | defaults as indicated by the validation spec. | |
463 | ||
464 | If the function is not called in a list context, providing a default | |
465 | in the validation spec still indicates that the parameter is optional. | |
466 | ||
467 | The hash or array returned from the function will always be a copy of | |
468 | the original parameters, in order to leave `@_` untouched for the | |
469 | calling function. | |
470 | ||
471 | Simple examples of defaults would be: | |
472 | ||
473 | my %p = validate( @_, { foo => 1, bar => { default => 99 } } ); | |
474 | ||
475 | my @p = validate_pos( @_, 1, { default => 99 } ); | |
476 | ||
477 | In scalar context, a hash reference or array reference will be | |
478 | returned, as appropriate. | |
479 | ||
480 | # USAGE NOTES | |
481 | ||
482 | ## Validation failure | |
483 | ||
484 | By default, when validation fails `Params::Validate` calls | |
485 | `Carp::confess()`. This can be overridden by setting the `on_fail` | |
486 | option, which is described in the ["GLOBAL" OPTIONS](https://metacpan.org/pod/"GLOBAL" OPTIONS) | |
487 | section. | |
488 | ||
489 | ## Method calls | |
490 | ||
491 | When using this module to validate the parameters passed to a method | |
492 | call, you will probably want to remove the class/object from the | |
493 | parameter list **before** calling `validate()` or `validate_pos()`. | |
494 | If your method expects named parameters, then this is necessary for | |
495 | the `validate()` function to actually work, otherwise `@_` will not | |
496 | be usable as a hash, because it will first have your object (or | |
497 | class) **followed** by a set of keys and values. | |
498 | ||
499 | Thus the idiomatic usage of `validate()` in a method call will look | |
500 | something like this: | |
501 | ||
502 | sub method { | |
503 | my $self = shift; | |
504 | ||
505 | my %params = validate( | |
382 | 506 | @_, { |
383 | foo => { type => SCALAR, untaint => 1 }, | |
384 | bar => { type => ARRAYREF } | |
507 | foo => 1, | |
508 | bar => { type => ARRAYREF }, | |
385 | 509 | } |
386 | 510 | ); |
387 | ||
388 | This will untaint the "foo" parameter if the parameters are valid. | |
389 | ||
390 | Note that untainting is only done if all parameters are valid. Also, | |
391 | only the return values are untainted, not the original values passed | |
392 | into the validation function. | |
393 | ||
394 | Asking for untainting of a reference value will not do anything, as | |
395 | Params::Validate will only attempt to untaint the reference itself. | |
396 | ||
397 | Mandatory/Optional Revisited | |
398 | ||
399 | If you want to specify something such as type or interface, plus the | |
400 | fact that a parameter can be optional, do this: | |
401 | ||
402 | validate( | |
403 | @_, { | |
404 | foo => { type => SCALAR }, | |
405 | bar => { type => ARRAYREF, optional => 1 } | |
406 | } | |
407 | ); | |
408 | ||
409 | or this for positional parameters: | |
410 | ||
411 | validate_pos( | |
412 | @_, | |
413 | { type => SCALAR }, | |
414 | { type => ARRAYREF, optional => 1 } | |
415 | ); | |
416 | ||
417 | By default, parameters are assumed to be mandatory unless specified as | |
418 | optional. | |
419 | ||
420 | Dependencies | |
421 | ||
422 | It also possible to specify that a given optional parameter depends on | |
423 | the presence of one or more other optional parameters. | |
424 | ||
425 | validate( | |
426 | @_, { | |
427 | cc_number => { | |
428 | type => SCALAR, | |
429 | optional => 1, | |
430 | depends => [ 'cc_expiration', 'cc_holder_name' ], | |
431 | }, | |
432 | cc_expiration => { type => SCALAR, optional => 1 }, | |
433 | cc_holder_name => { type => SCALAR, optional => 1 }, | |
434 | } | |
435 | ); | |
436 | ||
437 | In this case, "cc_number", "cc_expiration", and "cc_holder_name" are | |
438 | all optional. However, if "cc_number" is provided, then "cc_expiration" | |
439 | and "cc_holder_name" must be provided as well. | |
440 | ||
441 | This allows you to group together sets of parameters that all must be | |
442 | provided together. | |
443 | ||
444 | The validate_pos() version of dependencies is slightly different, in | |
445 | that you can only depend on one other parameter. Also, if for example, | |
446 | the second parameter 2 depends on the fourth parameter, then it implies | |
447 | a dependency on the third parameter as well. This is because if the | |
448 | fourth parameter is required, then the user must also provide a third | |
449 | parameter so that there can be four parameters in total. | |
450 | ||
451 | Params::Validate will die if you try to depend on a parameter not | |
452 | declared as part of your parameter specification. | |
453 | ||
454 | Specifying defaults | |
455 | ||
456 | If the validate() or validate_pos() functions are called in a list | |
457 | context, they will return a hash or containing the original parameters | |
458 | plus defaults as indicated by the validation spec. | |
459 | ||
460 | If the function is not called in a list context, providing a default in | |
461 | the validation spec still indicates that the parameter is optional. | |
462 | ||
463 | The hash or array returned from the function will always be a copy of | |
464 | the original parameters, in order to leave @_ untouched for the calling | |
465 | function. | |
466 | ||
467 | Simple examples of defaults would be: | |
468 | ||
469 | my %p = validate( @_, { foo => 1, bar => { default => 99 } } ); | |
470 | ||
471 | my @p = validate_pos( @_, 1, { default => 99 } ); | |
472 | ||
473 | In scalar context, a hash reference or array reference will be | |
474 | returned, as appropriate. | |
475 | ||
476 | USAGE NOTES | |
477 | ||
478 | Validation failure | |
479 | ||
480 | By default, when validation fails Params::Validate calls | |
481 | Carp::confess(). This can be overridden by setting the on_fail option, | |
482 | which is described in the "GLOBAL" OPTIONS section. | |
483 | ||
484 | Method calls | |
485 | ||
486 | When using this module to validate the parameters passed to a method | |
487 | call, you will probably want to remove the class/object from the | |
488 | parameter list before calling validate() or validate_pos(). If your | |
489 | method expects named parameters, then this is necessary for the | |
490 | validate() function to actually work, otherwise @_ will not be usable | |
491 | as a hash, because it will first have your object (or class) followed | |
492 | by a set of keys and values. | |
493 | ||
494 | Thus the idiomatic usage of validate() in a method call will look | |
495 | something like this: | |
496 | ||
497 | sub method { | |
498 | my $self = shift; | |
499 | ||
500 | my %params = validate( | |
501 | @_, { | |
502 | foo => 1, | |
503 | bar => { type => ARRAYREF }, | |
504 | } | |
511 | } | |
512 | ||
513 | ## Speeding Up Validation | |
514 | ||
515 | In most cases, the validation spec will remain the same for each call to a | |
516 | subroutine. In that case, you can speed up validation by defining the | |
517 | validation spec just once, rather than on each call to the subroutine: | |
518 | ||
519 | my %spec = ( ... ); | |
520 | sub foo { | |
521 | my %params = validate( @_, \%spec ); | |
522 | } | |
523 | ||
524 | You can also use the `state` feature to do this: | |
525 | ||
526 | use feature 'state'; | |
527 | ||
528 | sub foo { | |
529 | state $spec = { ... }; | |
530 | my %params = validate( @_, $spec ); | |
531 | } | |
532 | ||
533 | # "GLOBAL" OPTIONS | |
534 | ||
535 | Because the API for the `validate()` and `validate_pos()` functions does not | |
536 | make it possible to specify any options other than the validation spec, it is | |
537 | possible to set some options as pseudo-'globals'. These allow you to specify | |
538 | such things as whether or not the validation of named parameters should be | |
539 | case sensitive, for one example. | |
540 | ||
541 | These options are called pseudo-'globals' because these settings are | |
542 | **only applied to calls originating from the package that set the | |
543 | options**. | |
544 | ||
545 | In other words, if I am in package `Foo` and I call | |
546 | `validation_options()`, those options are only in effect when I call | |
547 | `validate()` from package `Foo`. | |
548 | ||
549 | While this is quite different from how most other modules operate, I | |
550 | feel that this is necessary in able to make it possible for one | |
551 | module/application to use Params::Validate while still using other | |
552 | modules that also use Params::Validate, perhaps with different | |
553 | options set. | |
554 | ||
555 | The downside to this is that if you are writing an app with a standard | |
556 | calling style for all functions, and your app has ten modules, **each | |
557 | module must include a call to `validation_options()`**. You could of | |
558 | course write a module that all your modules use which uses various | |
559 | trickery to do this when imported. | |
560 | ||
561 | ## Options | |
562 | ||
563 | - normalize\_keys => $callback | |
564 | ||
565 | This option is only relevant when dealing with named parameters. | |
566 | ||
567 | This callback will be used to transform the hash keys of both the | |
568 | parameters and the parameter spec when `validate()` or | |
569 | `validate_with()` are called. | |
570 | ||
571 | Any alterations made by this callback will be reflected in the | |
572 | parameter hash that is returned by the validation function. For | |
573 | example: | |
574 | ||
575 | sub foo { | |
576 | return validate_with( | |
577 | params => \@_, | |
578 | spec => { foo => { type => SCALAR } }, | |
579 | normalize_keys => | |
580 | sub { my $k = shift; $k =~ s/^-//; return uc $k }, | |
505 | 581 | ); |
582 | ||
506 | 583 | } |
507 | 584 | |
508 | Speeding Up Validation | |
509 | ||
510 | In most cases, the validation spec will remain the same for each call | |
511 | to a subroutine. In that case, you can speed up validation by defining | |
512 | the validation spec just once, rather than on each call to the | |
513 | subroutine: | |
514 | ||
515 | my %spec = ( ... ); | |
516 | sub foo { | |
517 | my %params = validate( @_, \%spec ); | |
518 | } | |
519 | ||
520 | You can also use the state feature to do this: | |
521 | ||
522 | use feature 'state'; | |
523 | ||
524 | sub foo { | |
525 | state $spec = { ... }; | |
526 | my %params = validate( @_, $spec ); | |
527 | } | |
528 | ||
529 | "GLOBAL" OPTIONS | |
530 | ||
531 | Because the API for the validate() and validate_pos() functions does | |
532 | not make it possible to specify any options other than the validation | |
533 | spec, it is possible to set some options as pseudo-'globals'. These | |
534 | allow you to specify such things as whether or not the validation of | |
535 | named parameters should be case sensitive, for one example. | |
536 | ||
537 | These options are called pseudo-'globals' because these settings are | |
538 | only applied to calls originating from the package that set the | |
539 | options. | |
540 | ||
541 | In other words, if I am in package Foo and I call validation_options(), | |
542 | those options are only in effect when I call validate() from package | |
543 | Foo. | |
544 | ||
545 | While this is quite different from how most other modules operate, I | |
546 | feel that this is necessary in able to make it possible for one | |
547 | module/application to use Params::Validate while still using other | |
548 | modules that also use Params::Validate, perhaps with different options | |
549 | set. | |
550 | ||
551 | The downside to this is that if you are writing an app with a standard | |
552 | calling style for all functions, and your app has ten modules, each | |
553 | module must include a call to validation_options(). You could of course | |
554 | write a module that all your modules use which uses various trickery to | |
555 | do this when imported. | |
556 | ||
557 | Options | |
558 | ||
559 | * normalize_keys => $callback | |
560 | ||
561 | This option is only relevant when dealing with named parameters. | |
562 | ||
563 | This callback will be used to transform the hash keys of both the | |
564 | parameters and the parameter spec when validate() or validate_with() | |
565 | are called. | |
566 | ||
567 | Any alterations made by this callback will be reflected in the | |
568 | parameter hash that is returned by the validation function. For | |
569 | example: | |
570 | ||
571 | sub foo { | |
572 | return validate_with( | |
573 | params => \@_, | |
574 | spec => { foo => { type => SCALAR } }, | |
575 | normalize_keys => | |
576 | sub { my $k = shift; $k =~ s/^-//; return uc $k }, | |
577 | ); | |
578 | ||
579 | } | |
580 | ||
581 | %p = foo( foo => 20 ); | |
582 | ||
583 | # $p{FOO} is now 20 | |
584 | ||
585 | %p = foo( -fOo => 50 ); | |
586 | ||
587 | # $p{FOO} is now 50 | |
588 | ||
589 | The callback must return a defined value. | |
590 | ||
591 | If a callback is given then the deprecated "ignore_case" and | |
592 | "strip_leading" options are ignored. | |
593 | ||
594 | * allow_extra => $boolean | |
595 | ||
596 | If true, then the validation routine will allow extra parameters not | |
597 | named in the validation specification. In the case of positional | |
598 | parameters, this allows an unlimited number of maximum parameters | |
599 | (though a minimum may still be set). Defaults to false. | |
600 | ||
601 | * on_fail => $callback | |
602 | ||
603 | If given, this callback will be called whenever a validation check | |
604 | fails. It will be called with a single parameter, which will be a | |
605 | string describing the failure. This is useful if you wish to have | |
606 | this module throw exceptions as objects rather than as strings, for | |
607 | example. | |
608 | ||
609 | This callback is expected to die() internally. If it does not, the | |
610 | validation will proceed onwards, with unpredictable results. | |
611 | ||
612 | The default is to simply use the Carp module's confess() function. | |
613 | ||
614 | * stack_skip => $number | |
615 | ||
616 | This tells Params::Validate how many stack frames to skip when | |
617 | finding a subroutine name to use in error messages. By default, it | |
618 | looks one frame back, at the immediate caller to validate() or | |
619 | validate_pos(). If this option is set, then the given number of | |
620 | frames are skipped instead. | |
621 | ||
622 | * ignore_case => $boolean | |
623 | ||
624 | DEPRECATED | |
625 | ||
626 | This is only relevant when dealing with named parameters. If it is | |
627 | true, then the validation code will ignore the case of parameter | |
628 | names. Defaults to false. | |
629 | ||
630 | * strip_leading => $characters | |
631 | ||
632 | DEPRECATED | |
633 | ||
634 | This too is only relevant when dealing with named parameters. If this | |
635 | is given then any parameters starting with these characters will be | |
636 | considered equivalent to parameters without them entirely. For | |
637 | example, if this is specified as '-', then -foo and foo would be | |
638 | considered identical. | |
639 | ||
640 | PER-INVOCATION OPTIONS | |
641 | ||
642 | The validate_with() function can be used to set the options listed | |
643 | above on a per-invocation basis. For example: | |
644 | ||
645 | my %p = validate_with( | |
646 | params => \@_, | |
647 | spec => { | |
648 | foo => { type => SCALAR }, | |
649 | bar => { default => 10 } | |
650 | }, | |
651 | allow_extra => 1, | |
652 | ); | |
653 | ||
654 | In addition to the options listed above, it is also possible to set the | |
655 | option "called", which should be a string. This string will be used in | |
656 | any error messages caused by a failure to meet the validation spec. | |
657 | ||
658 | This subroutine will validate named parameters as a hash if the "spec" | |
659 | parameter is a hash reference. If it is an array reference, the | |
660 | parameters are assumed to be positional. | |
661 | ||
662 | my %p = validate_with( | |
663 | params => \@_, | |
664 | spec => { | |
665 | foo => { type => SCALAR }, | |
666 | bar => { default => 10 } | |
667 | }, | |
668 | allow_extra => 1, | |
669 | called => 'The Quux::Baz class constructor', | |
670 | ); | |
671 | ||
672 | my @p = validate_with( | |
673 | params => \@_, | |
674 | spec => [ | |
675 | { type => SCALAR }, | |
676 | { default => 10 } | |
677 | ], | |
678 | allow_extra => 1, | |
679 | called => 'The Quux::Baz class constructor', | |
680 | ); | |
681 | ||
682 | DISABLING VALIDATION | |
683 | ||
684 | If the environment variable PERL_NO_VALIDATION is set to something | |
685 | true, then validation is turned off. This may be useful if you only | |
686 | want to use this module during development but don't want the speed hit | |
687 | during production. | |
688 | ||
689 | The only error that will be caught will be when an odd number of | |
690 | parameters are passed into a function/method that expects a hash. | |
691 | ||
692 | If you want to selectively turn validation on and off at runtime, you | |
693 | can directly set the $Params::Validate::NO_VALIDATION global variable. | |
694 | It is strongly recommended that you localize any changes to this | |
695 | variable, because other modules you are using may expect validation to | |
696 | be on when they execute. For example: | |
697 | ||
698 | { | |
699 | local $Params::Validate::NO_VALIDATION = 1; | |
700 | ||
701 | # no error | |
702 | foo( bar => 2 ); | |
703 | } | |
704 | ||
705 | # error | |
585 | %p = foo( foo => 20 ); | |
586 | ||
587 | # $p{FOO} is now 20 | |
588 | ||
589 | %p = foo( -fOo => 50 ); | |
590 | ||
591 | # $p{FOO} is now 50 | |
592 | ||
593 | The callback must return a defined value. | |
594 | ||
595 | If a callback is given then the deprecated "ignore\_case" and | |
596 | "strip\_leading" options are ignored. | |
597 | ||
598 | - allow\_extra => $boolean | |
599 | ||
600 | If true, then the validation routine will allow extra parameters not | |
601 | named in the validation specification. In the case of positional | |
602 | parameters, this allows an unlimited number of maximum parameters | |
603 | (though a minimum may still be set). Defaults to false. | |
604 | ||
605 | - on\_fail => $callback | |
606 | ||
607 | If given, this callback will be called whenever a validation check | |
608 | fails. It will be called with a single parameter, which will be a | |
609 | string describing the failure. This is useful if you wish to have | |
610 | this module throw exceptions as objects rather than as strings, for | |
611 | example. | |
612 | ||
613 | This callback is expected to `die()` internally. If it does not, the | |
614 | validation will proceed onwards, with unpredictable results. | |
615 | ||
616 | The default is to simply use the Carp module's `confess()` function. | |
617 | ||
618 | - stack\_skip => $number | |
619 | ||
620 | This tells Params::Validate how many stack frames to skip when finding | |
621 | a subroutine name to use in error messages. By default, it looks one | |
622 | frame back, at the immediate caller to `validate()` or | |
623 | `validate_pos()`. If this option is set, then the given number of | |
624 | frames are skipped instead. | |
625 | ||
626 | - ignore\_case => $boolean | |
627 | ||
628 | DEPRECATED | |
629 | ||
630 | This is only relevant when dealing with named parameters. If it is | |
631 | true, then the validation code will ignore the case of parameter | |
632 | names. Defaults to false. | |
633 | ||
634 | - strip\_leading => $characters | |
635 | ||
636 | DEPRECATED | |
637 | ||
638 | This too is only relevant when dealing with named parameters. If this | |
639 | is given then any parameters starting with these characters will be | |
640 | considered equivalent to parameters without them entirely. For | |
641 | example, if this is specified as '-', then `-foo` and `foo` would be | |
642 | considered identical. | |
643 | ||
644 | # PER-INVOCATION OPTIONS | |
645 | ||
646 | The `validate_with()` function can be used to set the options listed | |
647 | above on a per-invocation basis. For example: | |
648 | ||
649 | my %p = validate_with( | |
650 | params => \@_, | |
651 | spec => { | |
652 | foo => { type => SCALAR }, | |
653 | bar => { default => 10 } | |
654 | }, | |
655 | allow_extra => 1, | |
656 | ); | |
657 | ||
658 | In addition to the options listed above, it is also possible to set | |
659 | the option "called", which should be a string. This string will be | |
660 | used in any error messages caused by a failure to meet the validation | |
661 | spec. | |
662 | ||
663 | This subroutine will validate named parameters as a hash if the "spec" | |
664 | parameter is a hash reference. If it is an array reference, the | |
665 | parameters are assumed to be positional. | |
666 | ||
667 | my %p = validate_with( | |
668 | params => \@_, | |
669 | spec => { | |
670 | foo => { type => SCALAR }, | |
671 | bar => { default => 10 } | |
672 | }, | |
673 | allow_extra => 1, | |
674 | called => 'The Quux::Baz class constructor', | |
675 | ); | |
676 | ||
677 | my @p = validate_with( | |
678 | params => \@_, | |
679 | spec => [ | |
680 | { type => SCALAR }, | |
681 | { default => 10 } | |
682 | ], | |
683 | allow_extra => 1, | |
684 | called => 'The Quux::Baz class constructor', | |
685 | ); | |
686 | ||
687 | # DISABLING VALIDATION | |
688 | ||
689 | If the environment variable `PERL_NO_VALIDATION` is set to something | |
690 | true, then validation is turned off. This may be useful if you only | |
691 | want to use this module during development but don't want the speed | |
692 | hit during production. | |
693 | ||
694 | The only error that will be caught will be when an odd number of | |
695 | parameters are passed into a function/method that expects a hash. | |
696 | ||
697 | If you want to selectively turn validation on and off at runtime, you | |
698 | can directly set the `$Params::Validate::NO_VALIDATION` global | |
699 | variable. It is **strongly** recommended that you **localize** any | |
700 | changes to this variable, because other modules you are using may | |
701 | expect validation to be on when they execute. For example: | |
702 | ||
703 | { | |
704 | local $Params::Validate::NO_VALIDATION = 1; | |
705 | ||
706 | # no error | |
706 | 707 | foo( bar => 2 ); |
707 | ||
708 | sub foo { | |
709 | my %p = validate( @_, { foo => 1 } ); | |
710 | ...; | |
711 | } | |
712 | ||
713 | But if you want to shoot yourself in the foot and just turn it off, go | |
714 | ahead! | |
715 | ||
716 | SPECIFYING AN IMPLEMENTATION | |
717 | ||
718 | This module ships with two equivalent implementations, one in XS and | |
719 | one in pure Perl. By default, it will try to load the XS version and | |
720 | fall back to the pure Perl implementation as needed. If you want to | |
721 | request a specific version, you can set the | |
722 | PARAMS_VALIDATE_IMPLEMENTATION environment variable to either XS or PP. | |
723 | If the implementation you ask for cannot be loaded, then this module | |
724 | will die when loaded. | |
725 | ||
726 | TAINT MODE | |
727 | ||
728 | The XS implementation of this module has some problems Under taint mode | |
729 | with version of Perl before 5.14. If validation fails, then instead of | |
730 | getting the expected error message you'll get a message like "Insecure | |
731 | dependency in eval_sv". This can be worked around by either untainting | |
732 | the arguments yourself, using the pure Perl implementation, or | |
733 | upgrading your Perl. | |
734 | ||
735 | LIMITATIONS | |
736 | ||
737 | Right now there is no way (short of a callback) to specify that | |
738 | something must be of one of a list of classes, or that it must possess | |
739 | one of a list of methods. If this is desired, it can be added in the | |
740 | future. | |
741 | ||
742 | Ideally, there would be only one validation function. If someone | |
743 | figures out how to do this, please let me know. | |
744 | ||
745 | SUPPORT | |
746 | ||
747 | Please submit bugs and patches to the CPAN RT system at | |
748 | http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Params%3A%3AValidate or | |
749 | via email at bug-params-validate@rt.cpan.org. | |
750 | ||
751 | Support questions can be sent to Dave at autarch@urth.org. | |
752 | ||
753 | DONATIONS | |
754 | ||
755 | If you'd like to thank me for the work I've done on this module, please | |
756 | consider making a "donation" to me via PayPal. I spend a lot of free | |
757 | time creating free software, and would appreciate any support you'd | |
758 | care to offer. | |
759 | ||
760 | Please note that I am not suggesting that you must do this in order for | |
761 | me to continue working on this particular software. I will continue to | |
762 | do so, inasmuch as I have in the past, for as long as it interests me. | |
763 | ||
764 | Similarly, a donation made in this way will probably not make me work | |
765 | on this software much more, unless I get so many donations that I can | |
766 | consider working on free software full time, which seems unlikely at | |
767 | best. | |
768 | ||
769 | To donate, log into PayPal and send money to autarch@urth.org or use | |
770 | the button on this page: http://www.urth.org/~autarch/fs-donation.html | |
771 | ||
772 | AUTHORS | |
773 | ||
774 | * Dave Rolsky <autarch@urth.org> | |
775 | ||
776 | * Ilya Martynov <ilya@martynov.org> | |
777 | ||
778 | CONTRIBUTORS | |
779 | ||
780 | * Ivan Bessarabov <ivan@bessarabov.ru> | |
781 | ||
782 | * J.R. Mash <jmash.code@gmail.com> | |
783 | ||
784 | * Noel Maddy <zhtwnpanta@gmail.com> | |
785 | ||
786 | * Olivier Mengué <dolmen@cpan.org> | |
787 | ||
788 | * Vincent Pit <perl@profvince.com> | |
789 | ||
790 | COPYRIGHT AND LICENSE | |
791 | ||
792 | This software is Copyright (c) 2001 - 2016 by Dave Rolsky and Ilya | |
793 | Martynov. | |
794 | ||
795 | This is free software, licensed under: | |
796 | ||
797 | The Artistic License 2.0 (GPL Compatible) | |
798 | ||
708 | } | |
709 | ||
710 | # error | |
711 | foo( bar => 2 ); | |
712 | ||
713 | sub foo { | |
714 | my %p = validate( @_, { foo => 1 } ); | |
715 | ...; | |
716 | } | |
717 | ||
718 | But if you want to shoot yourself in the foot and just turn it off, go | |
719 | ahead! | |
720 | ||
721 | # SPECIFYING AN IMPLEMENTATION | |
722 | ||
723 | This module ships with two equivalent implementations, one in XS and one in | |
724 | pure Perl. By default, it will try to load the XS version and fall back to the | |
725 | pure Perl implementation as needed. If you want to request a specific version, | |
726 | you can set the `PARAMS_VALIDATE_IMPLEMENTATION` environment variable to | |
727 | either `XS` or `PP`. If the implementation you ask for cannot be loaded, | |
728 | then this module will die when loaded. | |
729 | ||
730 | # TAINT MODE | |
731 | ||
732 | The XS implementation of this module has some problems Under taint mode with | |
733 | versions of Perl before 5.14. If validation _fails_, then instead of getting | |
734 | the expected error message you'll get a message like "Insecure dependency in | |
735 | eval\_sv". This can be worked around by either untainting the arguments | |
736 | yourself, using the pure Perl implementation, or upgrading your Perl. | |
737 | ||
738 | # LIMITATIONS | |
739 | ||
740 | Right now there is no way (short of a callback) to specify that | |
741 | something must be of one of a list of classes, or that it must possess | |
742 | one of a list of methods. If this is desired, it can be added in the | |
743 | future. | |
744 | ||
745 | Ideally, there would be only one validation function. If someone | |
746 | figures out how to do this, please let me know. | |
747 | ||
748 | # SUPPORT | |
749 | ||
750 | Bugs may be submitted through [the RT bug tracker](http://rt.cpan.org/Public/Dist/Display.html?Name=Params-Validate) | |
751 | (or [bug-params-validate@rt.cpan.org](mailto:bug-params-validate@rt.cpan.org)). | |
752 | ||
753 | I am also usually active on IRC as 'drolsky' on `irc://irc.perl.org`. | |
754 | ||
755 | # DONATIONS | |
756 | ||
757 | If you'd like to thank me for the work I've done on this module, please | |
758 | consider making a "donation" to me via PayPal. I spend a lot of free time | |
759 | creating free software, and would appreciate any support you'd care to offer. | |
760 | ||
761 | Please note that **I am not suggesting that you must do this** in order for me | |
762 | to continue working on this particular software. I will continue to do so, | |
763 | inasmuch as I have in the past, for as long as it interests me. | |
764 | ||
765 | Similarly, a donation made in this way will probably not make me work on this | |
766 | software much more, unless I get so many donations that I can consider working | |
767 | on free software full time (let's all have a chuckle at that together). | |
768 | ||
769 | To donate, log into PayPal and send money to autarch@urth.org, or use the | |
770 | button at [http://www.urth.org/~autarch/fs-donation.html](http://www.urth.org/~autarch/fs-donation.html). | |
771 | ||
772 | # AUTHORS | |
773 | ||
774 | - Dave Rolsky <autarch@urth.org> | |
775 | - Ilya Martynov <ilya@martynov.org> | |
776 | ||
777 | # CONTRIBUTORS | |
778 | ||
779 | - Ivan Bessarabov <ivan@bessarabov.ru> | |
780 | - J.R. Mash <jmash.code@gmail.com> | |
781 | - Noel Maddy <zhtwnpanta@gmail.com> | |
782 | - Olivier Mengué <dolmen@cpan.org> | |
783 | - Tony Cook <tony@develop-help.com> | |
784 | - Vincent Pit <perl@profvince.com> | |
785 | ||
786 | # COPYRIGHT AND LICENCE | |
787 | ||
788 | This software is Copyright (c) 2001 - 2016 by Dave Rolsky and Ilya Martynov. | |
789 | ||
790 | This is free software, licensed under: | |
791 | ||
792 | The Artistic License 2.0 (GPL Compatible) |
0 | 0 | requires "Carp" => "0"; |
1 | 1 | requires "Exporter" => "0"; |
2 | requires "JSON::PP" => "2.27300"; | |
3 | 2 | requires "Module::Implementation" => "0"; |
4 | 3 | requires "Scalar::Util" => "1.10"; |
5 | 4 | requires "XSLoader" => "0"; |
35 | 34 | requires "Module::Build" => "0.28"; |
36 | 35 | }; |
37 | 36 | |
37 | on 'configure' => sub { | |
38 | suggests "JSON::PP" => "2.27300"; | |
39 | }; | |
40 | ||
38 | 41 | on 'develop' => sub { |
39 | 42 | requires "File::Spec" => "0"; |
40 | 43 | requires "IO::Handle" => "0"; |
29 | 29 | stopwords = pre |
30 | 30 | stopwords = runtime |
31 | 31 | -remove = MakeMaker |
32 | -remove = Test::CleanNamespaces | |
32 | 33 | -remove = Test::TidyAll |
33 | 34 | -remove = Test::Version |
34 | 35 | |
43 | 44 | [=inc::MyModuleBuild] |
44 | 45 | |
45 | 46 | [PurePerlTests] |
47 | :version = 0.06 | |
46 | 48 | env_var = PV_TEST_PERL |
2 | 2 | use strict; |
3 | 3 | use warnings; |
4 | 4 | |
5 | our $VERSION = '1.22'; | |
5 | our $VERSION = '1.23'; | |
6 | 6 | |
7 | 7 | our @ISA = 'Exporter'; |
8 | 8 |
2 | 2 | use strict; |
3 | 3 | use warnings; |
4 | 4 | |
5 | our $VERSION = '1.22'; | |
5 | our $VERSION = '1.23'; | |
6 | 6 | |
7 | 7 | use Params::Validate::Constants; |
8 | 8 | use Scalar::Util 1.10 (); |
2 | 2 | use strict; |
3 | 3 | use warnings; |
4 | 4 | |
5 | our $VERSION = '1.22'; | |
5 | our $VERSION = '1.23'; | |
6 | 6 | |
7 | 7 | use Carp; |
8 | 8 |
778 | 778 | ok = POPi; |
779 | 779 | PUTBACK; |
780 | 780 | |
781 | if (!ok) { | |
781 | if (! ok) { | |
782 | 782 | SV* buffer = newSVpvf(id, string_representation(value)); |
783 | 783 | SV *caller = get_caller(options); |
784 | 784 | |
1606 | 1606 | AV* pa; |
1607 | 1607 | HV* ph; |
1608 | 1608 | HV* options; |
1609 | IV ok; | |
1609 | 1610 | |
1610 | 1611 | if (no_validation() && GIMME_V == G_VOID) { |
1611 | 1612 | XSRETURN(0); |
1642 | 1643 | if (! ph) { |
1643 | 1644 | ph = (HV*) sv_2mortal((SV*) newHV()); |
1644 | 1645 | |
1645 | if (! convert_array2hash(pa, options, ph) ) { | |
1646 | PUTBACK; | |
1647 | ok = convert_array2hash(pa, options, ph); | |
1648 | SPAGAIN; | |
1649 | ||
1650 | if (!ok) { | |
1646 | 1651 | XSRETURN(0); |
1647 | 1652 | } |
1648 | 1653 | } |
1649 | 1654 | if (GIMME_V != G_VOID) { |
1650 | 1655 | ret = (HV*) sv_2mortal((SV*) newHV()); |
1651 | 1656 | } |
1652 | if (! validate(ph, (HV*) SvRV(specs), options, ret)) { | |
1657 | ||
1658 | PUTBACK; | |
1659 | ok = validate(ph, (HV*) SvRV(specs), options, ret); | |
1660 | SPAGAIN; | |
1661 | ||
1662 | if (! ok) { | |
1653 | 1663 | XSRETURN(0); |
1654 | 1664 | } |
1665 | ||
1655 | 1666 | RETURN_HASH(ret); |
1656 | 1667 | |
1657 | 1668 | void |
1665 | 1676 | AV* specs; |
1666 | 1677 | AV* ret = NULL; |
1667 | 1678 | IV i; |
1679 | IV ok; | |
1668 | 1680 | |
1669 | 1681 | if (no_validation() && GIMME_V == G_VOID) { |
1670 | 1682 | XSRETURN(0); |
1688 | 1700 | ret = (AV*) sv_2mortal((SV*) newAV()); |
1689 | 1701 | } |
1690 | 1702 | |
1691 | if (! validate_pos((AV*) SvRV(p), specs, get_options(NULL), ret)) { | |
1703 | PUTBACK; | |
1704 | ok = validate_pos((AV*) SvRV(p), specs, get_options(NULL), ret); | |
1705 | SPAGAIN; | |
1706 | ||
1707 | if (! ok) { | |
1692 | 1708 | XSRETURN(0); |
1693 | 1709 | } |
1694 | 1710 | |
1703 | 1719 | SV* params; |
1704 | 1720 | SV* spec; |
1705 | 1721 | IV i; |
1722 | IV ok; | |
1706 | 1723 | |
1707 | 1724 | if (no_validation() && GIMME_V == G_VOID) XSRETURN(0); |
1708 | 1725 | |
1739 | 1756 | } |
1740 | 1757 | |
1741 | 1758 | PUTBACK; |
1742 | ||
1743 | if (! validate_pos((AV*) SvRV(params), (AV*) SvRV(spec), get_options(p), ret)) { | |
1744 | SPAGAIN; | |
1759 | ok = validate_pos((AV*) SvRV(params), (AV*) SvRV(spec), get_options(p), ret); | |
1760 | SPAGAIN; | |
1761 | ||
1762 | if (! ok) { | |
1745 | 1763 | XSRETURN(0); |
1746 | 1764 | } |
1747 | 1765 | |
1748 | SPAGAIN; | |
1749 | 1766 | RETURN_ARRAY(ret); |
1750 | 1767 | } |
1751 | 1768 | else { |
1783 | 1800 | if (! hv_set) { |
1784 | 1801 | hv = (HV*) sv_2mortal((SV*) newHV()); |
1785 | 1802 | |
1786 | if (! convert_array2hash((AV*) SvRV(params), options, hv)) | |
1803 | PUTBACK; | |
1804 | ok = convert_array2hash((AV*) SvRV(params), options, hv); | |
1805 | SPAGAIN; | |
1806 | ||
1807 | if (!ok) { | |
1787 | 1808 | XSRETURN(0); |
1809 | } | |
1788 | 1810 | } |
1789 | 1811 | } |
1790 | 1812 | else { |
1796 | 1818 | } |
1797 | 1819 | |
1798 | 1820 | PUTBACK; |
1799 | ||
1800 | if (! validate(hv, (HV*) SvRV(spec), options, ret)) { | |
1801 | SPAGAIN; | |
1821 | ok = validate(hv, (HV*) SvRV(spec), options, ret); | |
1822 | SPAGAIN; | |
1823 | ||
1824 | if (! ok) { | |
1802 | 1825 | XSRETURN(0); |
1803 | 1826 | } |
1804 | 1827 | |
1805 | SPAGAIN; | |
1806 | 1828 | RETURN_HASH(ret); |
1807 | 1829 | } |
1808 | 1830 | else { |
4 | 4 | use strict; |
5 | 5 | use warnings; |
6 | 6 | |
7 | our $VERSION = '1.22'; | |
7 | our $VERSION = '1.23'; | |
8 | 8 | |
9 | 9 | use Exporter; |
10 | 10 | use Module::Implementation; |
68 | 68 | |
69 | 69 | =pod |
70 | 70 | |
71 | =encoding UTF-8 | |
72 | ||
71 | 73 | =head1 NAME |
72 | 74 | |
73 | 75 | Params::Validate - Validate method/function parameters |
74 | 76 | |
75 | 77 | =head1 VERSION |
76 | 78 | |
77 | version 1.22 | |
79 | version 1.23 | |
78 | 80 | |
79 | 81 | =head1 SYNOPSIS |
80 | 82 | |
186 | 188 | also an C<:all> tag which includes all of the constants as well as the |
187 | 189 | C<validation_options()> function. |
188 | 190 | |
189 | =encoding UTF-8 | |
190 | ||
191 | 191 | =head1 PARAMETER VALIDATION |
192 | 192 | |
193 | 193 | The validation mechanisms provided by this module can handle both |
811 | 811 | =head1 TAINT MODE |
812 | 812 | |
813 | 813 | The XS implementation of this module has some problems Under taint mode with |
814 | version of Perl before 5.14. If validation I<fails>, then instead of getting | |
814 | versions of Perl before 5.14. If validation I<fails>, then instead of getting | |
815 | 815 | the expected error message you'll get a message like "Insecure dependency in |
816 | 816 | eval_sv". This can be worked around by either untainting the arguments |
817 | 817 | yourself, using the pure Perl implementation, or upgrading your Perl. |
828 | 828 | |
829 | 829 | =head1 SUPPORT |
830 | 830 | |
831 | Please submit bugs and patches to the CPAN RT system at | |
832 | http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Params%3A%3AValidate or | |
833 | via email at bug-params-validate@rt.cpan.org. | |
834 | ||
835 | Support questions can be sent to Dave at autarch@urth.org. | |
831 | Bugs may be submitted through L<the RT bug tracker|http://rt.cpan.org/Public/Dist/Display.html?Name=Params-Validate> | |
832 | (or L<bug-params-validate@rt.cpan.org|mailto:bug-params-validate@rt.cpan.org>). | |
833 | ||
834 | I am also usually active on IRC as 'drolsky' on C<irc://irc.perl.org>. | |
836 | 835 | |
837 | 836 | =head1 DONATIONS |
838 | 837 | |
839 | If you'd like to thank me for the work I've done on this module, | |
840 | please consider making a "donation" to me via PayPal. I spend a lot of | |
841 | free time creating free software, and would appreciate any support | |
842 | you'd care to offer. | |
843 | ||
844 | Please note that B<I am not suggesting that you must do this> in order | |
845 | for me to continue working on this particular software. I will | |
846 | continue to do so, inasmuch as I have in the past, for as long as it | |
847 | interests me. | |
848 | ||
849 | Similarly, a donation made in this way will probably not make me work | |
850 | on this software much more, unless I get so many donations that I can | |
851 | consider working on free software full time, which seems unlikely at | |
852 | best. | |
853 | ||
854 | To donate, log into PayPal and send money to autarch@urth.org or use | |
855 | the button on this page: | |
856 | L<http://www.urth.org/~autarch/fs-donation.html> | |
838 | If you'd like to thank me for the work I've done on this module, please | |
839 | consider making a "donation" to me via PayPal. I spend a lot of free time | |
840 | creating free software, and would appreciate any support you'd care to offer. | |
841 | ||
842 | Please note that B<I am not suggesting that you must do this> in order for me | |
843 | to continue working on this particular software. I will continue to do so, | |
844 | inasmuch as I have in the past, for as long as it interests me. | |
845 | ||
846 | Similarly, a donation made in this way will probably not make me work on this | |
847 | software much more, unless I get so many donations that I can consider working | |
848 | on free software full time (let's all have a chuckle at that together). | |
849 | ||
850 | To donate, log into PayPal and send money to autarch@urth.org, or use the | |
851 | button at L<http://www.urth.org/~autarch/fs-donation.html>. | |
857 | 852 | |
858 | 853 | =head1 AUTHORS |
859 | 854 | |
871 | 866 | |
872 | 867 | =head1 CONTRIBUTORS |
873 | 868 | |
874 | =for stopwords Ivan Bessarabov J.R. Mash Noel Maddy Olivier Mengué Vincent Pit | |
869 | =for stopwords Ivan Bessarabov J.R. Mash Noel Maddy Olivier Mengué Tony Cook Vincent Pit | |
875 | 870 | |
876 | 871 | =over 4 |
877 | 872 | |
893 | 888 | |
894 | 889 | =item * |
895 | 890 | |
891 | Tony Cook <tony@develop-help.com> | |
892 | ||
893 | =item * | |
894 | ||
896 | 895 | Vincent Pit <perl@profvince.com> |
897 | 896 | |
898 | 897 | =back |
899 | 898 | |
900 | =head1 COPYRIGHT AND LICENSE | |
899 | =head1 COPYRIGHT AND LICENCE | |
901 | 900 | |
902 | 901 | This software is Copyright (c) 2001 - 2016 by Dave Rolsky and Ilya Martynov. |
903 | 902 |
0 | 0 | package # hide from PAUSE |
1 | 1 | Params::Validate; |
2 | 2 | |
3 | our $VERSION = '1.22'; | |
3 | our $VERSION = '1.23'; | |
4 | 4 | |
5 | 5 | BEGIN { $ENV{PARAMS_VALIDATE_IMPLEMENTATION} = 'PP' } |
6 | 6 | use Params::Validate; |
0 | 0 | package # hide from PAUSE |
1 | 1 | Params::Validate; |
2 | 2 | |
3 | our $VERSION = '1.22'; | |
3 | our $VERSION = '1.23'; | |
4 | 4 | |
5 | 5 | BEGIN { $ENV{PARAMS_VALIDATE_IMPLEMENTATION} = 'XS' } |
6 | 6 | use Params::Validate; |
6 | 6 | 'configure' => { |
7 | 7 | 'requires' => { |
8 | 8 | 'Module::Build' => '0.28' |
9 | }, | |
10 | 'suggests' => { | |
11 | 'JSON::PP' => '2.27300' | |
9 | 12 | } |
10 | 13 | }, |
11 | 14 | 'develop' => { |
38 | 41 | 'requires' => { |
39 | 42 | 'Carp' => '0', |
40 | 43 | 'Exporter' => '0', |
41 | 'JSON::PP' => '2.27300', | |
42 | 44 | 'Module::Implementation' => '0', |
43 | 45 | 'Scalar::Util' => '1.10', |
44 | 46 | 'XSLoader' => '0', |
2 | 2 | use strict; |
3 | 3 | use warnings; |
4 | 4 | |
5 | # This test was generated by Dist::Zilla::Plugin::Test::ReportPrereqs 0.021 | |
5 | # This test was generated by Dist::Zilla::Plugin::Test::ReportPrereqs 0.024 | |
6 | 6 | |
7 | 7 | use Test::More tests => 1; |
8 | 8 |
15 | 15 | { type => SCALAR, optional => 1, default => 'must be second one' }, |
16 | 16 | ); |
17 | 17 | |
18 | is( $first, undef, '01 no default for first' ); | |
19 | is( $second, 'must be second one', '01 default for second' ); | |
18 | is( $first, undef, 'no default for first parameter' ); | |
19 | is( $second, 'must be second one', | |
20 | 'default for second parameter is applied' ); | |
20 | 21 | } |
88 | 88 | |
89 | 89 | like( |
90 | 90 | $e, |
91 | qr/\QThe 'string' parameter (\E.+?\Q) to main::validate4 did not pass the 'string' callback\E\s+at/, | |
91 | qr/\QThe 'string' parameter (\E.+?\Q) to main::validate4 did not pass the 'string' callback/, | |
92 | 92 | 'callback that does not dies generates a sane error message' |
93 | 93 | ); |
94 | 94 | } |
61 | 61 | 't/39-reentrant.t', |
62 | 62 | 't/author-00-compile.t', |
63 | 63 | 't/author-eol.t', |
64 | 't/author-memory-leak.t', | |
64 | 65 | 't/author-mojibake.t', |
65 | 66 | 't/author-no-tabs.t', |
66 | 67 | 't/author-pod-spell.t', |
67 | 68 | 't/author-pod-syntax.t', |
69 | 't/author-pp-01-validate.t', | |
70 | 't/author-pp-02-noop.t', | |
71 | 't/author-pp-04-defaults.t', | |
72 | 't/author-pp-05-noop_default.t', | |
73 | 't/author-pp-06-options.t', | |
74 | 't/author-pp-07-with.t', | |
75 | 't/author-pp-08-noop_with.t', | |
76 | 't/author-pp-09-regex.t', | |
77 | 't/author-pp-10-noop_regex.t', | |
78 | 't/author-pp-11-cb.t', | |
79 | 't/author-pp-12-noop_cb.t', | |
80 | 't/author-pp-13-taint.t', | |
81 | 't/author-pp-14-no_validate.t', | |
82 | 't/author-pp-15-case.t', | |
83 | 't/author-pp-16-normalize.t', | |
84 | 't/author-pp-17-callbacks.t', | |
85 | 't/author-pp-18-depends.t', | |
86 | 't/author-pp-19-untaint.t', | |
87 | 't/author-pp-21-can.t', | |
88 | 't/author-pp-22-overload-can-bug.t', | |
89 | 't/author-pp-23-readonly.t', | |
90 | 't/author-pp-24-tied.t', | |
91 | 't/author-pp-25-undef-regex.t', | |
92 | 't/author-pp-26-isa.t', | |
93 | 't/author-pp-27-string-as-type.t', | |
94 | 't/author-pp-28-readonly-return.t', | |
95 | 't/author-pp-29-taint-mode.t', | |
96 | 't/author-pp-30-hashref-alteration.t', | |
97 | 't/author-pp-31-incorrect-spelling.t', | |
98 | 't/author-pp-32-regex-as-value.t', | |
99 | 't/author-pp-33-keep-errsv.t', | |
100 | 't/author-pp-34-recursive-validation.t', | |
101 | 't/author-pp-35-default-xs-bug.t', | |
102 | 't/author-pp-36-large-arrays.t', | |
103 | 't/author-pp-37-exports.t', | |
104 | 't/author-pp-38-callback-message.t', | |
105 | 't/author-pp-39-reentrant.t', | |
106 | 't/author-pp-is-loaded.t', | |
107 | 't/author-xs-is-loaded.t', | |
108 | 't/author-xs-segfault.t', | |
109 | 't/author-xs-stack-realloc.t', | |
68 | 110 | 't/lib/PVTests.pm', |
69 | 111 | 't/lib/PVTests/Callbacks.pm', |
70 | 112 | 't/lib/PVTests/Defaults.pm', |
72 | 114 | 't/lib/PVTests/Standard.pm', |
73 | 115 | 't/lib/PVTests/With.pm', |
74 | 116 | 't/release-cpan-changes.t', |
75 | 't/release-memory-leak.t', | |
76 | 117 | 't/release-meta-json.t', |
77 | 118 | 't/release-pod-coverage.t', |
78 | 119 | 't/release-pod-linkcheck.t', |
79 | 120 | 't/release-pod-no404s.t', |
80 | 121 | 't/release-portability.t', |
81 | 't/release-pp-01-validate.t', | |
82 | 't/release-pp-02-noop.t', | |
83 | 't/release-pp-04-defaults.t', | |
84 | 't/release-pp-05-noop_default.t', | |
85 | 't/release-pp-06-options.t', | |
86 | 't/release-pp-07-with.t', | |
87 | 't/release-pp-08-noop_with.t', | |
88 | 't/release-pp-09-regex.t', | |
89 | 't/release-pp-10-noop_regex.t', | |
90 | 't/release-pp-11-cb.t', | |
91 | 't/release-pp-12-noop_cb.t', | |
92 | 't/release-pp-13-taint.t', | |
93 | 't/release-pp-14-no_validate.t', | |
94 | 't/release-pp-15-case.t', | |
95 | 't/release-pp-16-normalize.t', | |
96 | 't/release-pp-17-callbacks.t', | |
97 | 't/release-pp-18-depends.t', | |
98 | 't/release-pp-19-untaint.t', | |
99 | 't/release-pp-21-can.t', | |
100 | 't/release-pp-22-overload-can-bug.t', | |
101 | 't/release-pp-23-readonly.t', | |
102 | 't/release-pp-24-tied.t', | |
103 | 't/release-pp-25-undef-regex.t', | |
104 | 't/release-pp-26-isa.t', | |
105 | 't/release-pp-27-string-as-type.t', | |
106 | 't/release-pp-28-readonly-return.t', | |
107 | 't/release-pp-29-taint-mode.t', | |
108 | 't/release-pp-30-hashref-alteration.t', | |
109 | 't/release-pp-31-incorrect-spelling.t', | |
110 | 't/release-pp-32-regex-as-value.t', | |
111 | 't/release-pp-33-keep-errsv.t', | |
112 | 't/release-pp-34-recursive-validation.t', | |
113 | 't/release-pp-35-default-xs-bug.t', | |
114 | 't/release-pp-36-large-arrays.t', | |
115 | 't/release-pp-37-exports.t', | |
116 | 't/release-pp-38-callback-message.t', | |
117 | 't/release-pp-39-reentrant.t', | |
118 | 't/release-pp-is-loaded.t', | |
119 | 't/release-synopsis.t', | |
120 | 't/release-xs-is-loaded.t', | |
121 | 't/release-xs-segfault.t', | |
122 | 't/release-xs-stack-realloc.t' | |
122 | 't/release-synopsis.t' | |
123 | 123 | ); |
124 | 124 | |
125 | 125 | eol_unix_ok($_, { trailing_whitespace => 1 }) foreach @files; |
0 | ||
1 | BEGIN { | |
2 | unless ($ENV{AUTHOR_TESTING}) { | |
3 | require Test::More; | |
4 | Test::More::plan(skip_all => 'these tests are for testing by the author'); | |
5 | } | |
6 | } | |
7 | ||
8 | use strict; | |
9 | use warnings; | |
10 | ||
11 | use Test::LeakTrace qw( no_leaks_ok ); | |
12 | use Test::More; | |
13 | ||
14 | use Params::Validate qw( validate ); | |
15 | ||
16 | subtest( | |
17 | 'callback with default error' => sub { | |
18 | no_leaks_ok( sub { val1( foo => 42 ); }, 'validation passes' ); | |
19 | local $TODO = 'Not sure if all the leaks are in Carp or not'; | |
20 | no_leaks_ok( | |
21 | sub { | |
22 | eval { val1( foo => 'forty two' ) }; | |
23 | }, | |
24 | 'validation fails' | |
25 | ); | |
26 | }, | |
27 | ); | |
28 | ||
29 | subtest( | |
30 | 'callback that dies with string' => sub { | |
31 | no_leaks_ok( sub { val2( foo => 42 ); }, 'validation passes' ); | |
32 | local $TODO = 'Not sure if all the leaks are in Carp or not'; | |
33 | no_leaks_ok( | |
34 | sub { | |
35 | eval { val2( foo => 'forty two' ) }; | |
36 | }, | |
37 | 'validation fails' | |
38 | ); | |
39 | }, | |
40 | ); | |
41 | ||
42 | subtest( | |
43 | 'callback that dies with object' => sub { | |
44 | no_leaks_ok( sub { val3( foo => 42 ); }, 'validation passes' ); | |
45 | no_leaks_ok( | |
46 | sub { | |
47 | eval { val3( foo => 'forty two' ) }; | |
48 | }, | |
49 | 'validation fails' | |
50 | ); | |
51 | }, | |
52 | ); | |
53 | ||
54 | done_testing(); | |
55 | ||
56 | sub val1 { | |
57 | validate( | |
58 | @_, | |
59 | { | |
60 | foo => { | |
61 | callbacks => { | |
62 | 'is int' => sub { $_[0] =~ /^[0-9]+$/ } | |
63 | } | |
64 | }, | |
65 | }, | |
66 | ); | |
67 | } | |
68 | ||
69 | sub val2 { | |
70 | validate( | |
71 | @_, | |
72 | { | |
73 | foo => { | |
74 | callbacks => { | |
75 | 'is int' => sub { | |
76 | $_[0] =~ /^[0-9]+$/ or die "$_[0] is not an integer"; | |
77 | } | |
78 | } | |
79 | }, | |
80 | }, | |
81 | ); | |
82 | } | |
83 | ||
84 | sub val3 { | |
85 | validate( | |
86 | @_, | |
87 | { | |
88 | foo => { | |
89 | callbacks => { | |
90 | 'is int' => sub { | |
91 | $_[0] =~ /^[0-9]+$/ | |
92 | or die { error => "$_[0] is not an integer" }; | |
93 | } | |
94 | } | |
95 | }, | |
96 | }, | |
97 | ); | |
98 | } |
61 | 61 | 't/39-reentrant.t', |
62 | 62 | 't/author-00-compile.t', |
63 | 63 | 't/author-eol.t', |
64 | 't/author-memory-leak.t', | |
64 | 65 | 't/author-mojibake.t', |
65 | 66 | 't/author-no-tabs.t', |
66 | 67 | 't/author-pod-spell.t', |
67 | 68 | 't/author-pod-syntax.t', |
69 | 't/author-pp-01-validate.t', | |
70 | 't/author-pp-02-noop.t', | |
71 | 't/author-pp-04-defaults.t', | |
72 | 't/author-pp-05-noop_default.t', | |
73 | 't/author-pp-06-options.t', | |
74 | 't/author-pp-07-with.t', | |
75 | 't/author-pp-08-noop_with.t', | |
76 | 't/author-pp-09-regex.t', | |
77 | 't/author-pp-10-noop_regex.t', | |
78 | 't/author-pp-11-cb.t', | |
79 | 't/author-pp-12-noop_cb.t', | |
80 | 't/author-pp-13-taint.t', | |
81 | 't/author-pp-14-no_validate.t', | |
82 | 't/author-pp-15-case.t', | |
83 | 't/author-pp-16-normalize.t', | |
84 | 't/author-pp-17-callbacks.t', | |
85 | 't/author-pp-18-depends.t', | |
86 | 't/author-pp-19-untaint.t', | |
87 | 't/author-pp-21-can.t', | |
88 | 't/author-pp-22-overload-can-bug.t', | |
89 | 't/author-pp-23-readonly.t', | |
90 | 't/author-pp-24-tied.t', | |
91 | 't/author-pp-25-undef-regex.t', | |
92 | 't/author-pp-26-isa.t', | |
93 | 't/author-pp-27-string-as-type.t', | |
94 | 't/author-pp-28-readonly-return.t', | |
95 | 't/author-pp-29-taint-mode.t', | |
96 | 't/author-pp-30-hashref-alteration.t', | |
97 | 't/author-pp-31-incorrect-spelling.t', | |
98 | 't/author-pp-32-regex-as-value.t', | |
99 | 't/author-pp-33-keep-errsv.t', | |
100 | 't/author-pp-34-recursive-validation.t', | |
101 | 't/author-pp-35-default-xs-bug.t', | |
102 | 't/author-pp-36-large-arrays.t', | |
103 | 't/author-pp-37-exports.t', | |
104 | 't/author-pp-38-callback-message.t', | |
105 | 't/author-pp-39-reentrant.t', | |
106 | 't/author-pp-is-loaded.t', | |
107 | 't/author-xs-is-loaded.t', | |
108 | 't/author-xs-segfault.t', | |
109 | 't/author-xs-stack-realloc.t', | |
68 | 110 | 't/lib/PVTests.pm', |
69 | 111 | 't/lib/PVTests/Callbacks.pm', |
70 | 112 | 't/lib/PVTests/Defaults.pm', |
72 | 114 | 't/lib/PVTests/Standard.pm', |
73 | 115 | 't/lib/PVTests/With.pm', |
74 | 116 | 't/release-cpan-changes.t', |
75 | 't/release-memory-leak.t', | |
76 | 117 | 't/release-meta-json.t', |
77 | 118 | 't/release-pod-coverage.t', |
78 | 119 | 't/release-pod-linkcheck.t', |
79 | 120 | 't/release-pod-no404s.t', |
80 | 121 | 't/release-portability.t', |
81 | 't/release-pp-01-validate.t', | |
82 | 't/release-pp-02-noop.t', | |
83 | 't/release-pp-04-defaults.t', | |
84 | 't/release-pp-05-noop_default.t', | |
85 | 't/release-pp-06-options.t', | |
86 | 't/release-pp-07-with.t', | |
87 | 't/release-pp-08-noop_with.t', | |
88 | 't/release-pp-09-regex.t', | |
89 | 't/release-pp-10-noop_regex.t', | |
90 | 't/release-pp-11-cb.t', | |
91 | 't/release-pp-12-noop_cb.t', | |
92 | 't/release-pp-13-taint.t', | |
93 | 't/release-pp-14-no_validate.t', | |
94 | 't/release-pp-15-case.t', | |
95 | 't/release-pp-16-normalize.t', | |
96 | 't/release-pp-17-callbacks.t', | |
97 | 't/release-pp-18-depends.t', | |
98 | 't/release-pp-19-untaint.t', | |
99 | 't/release-pp-21-can.t', | |
100 | 't/release-pp-22-overload-can-bug.t', | |
101 | 't/release-pp-23-readonly.t', | |
102 | 't/release-pp-24-tied.t', | |
103 | 't/release-pp-25-undef-regex.t', | |
104 | 't/release-pp-26-isa.t', | |
105 | 't/release-pp-27-string-as-type.t', | |
106 | 't/release-pp-28-readonly-return.t', | |
107 | 't/release-pp-29-taint-mode.t', | |
108 | 't/release-pp-30-hashref-alteration.t', | |
109 | 't/release-pp-31-incorrect-spelling.t', | |
110 | 't/release-pp-32-regex-as-value.t', | |
111 | 't/release-pp-33-keep-errsv.t', | |
112 | 't/release-pp-34-recursive-validation.t', | |
113 | 't/release-pp-35-default-xs-bug.t', | |
114 | 't/release-pp-36-large-arrays.t', | |
115 | 't/release-pp-37-exports.t', | |
116 | 't/release-pp-38-callback-message.t', | |
117 | 't/release-pp-39-reentrant.t', | |
118 | 't/release-pp-is-loaded.t', | |
119 | 't/release-synopsis.t', | |
120 | 't/release-xs-is-loaded.t', | |
121 | 't/release-xs-segfault.t', | |
122 | 't/release-xs-stack-realloc.t' | |
122 | 't/release-synopsis.t' | |
123 | 123 | ); |
124 | 124 | |
125 | 125 | notabs_ok($_) foreach @files; |
17 | 17 | add_stopwords(<DATA>); |
18 | 18 | all_pod_files_spelling_ok( qw( bin lib ) ); |
19 | 19 | __DATA__ |
20 | drolsky | |
20 | 21 | DROLSKY |
21 | 22 | DROLSKY's |
22 | 23 | PayPal |
49 | 50 | Olivier |
50 | 51 | Mengué |
51 | 52 | dolmen |
53 | Tony | |
54 | Cook | |
55 | tony | |
52 | 56 | Vincent |
53 | 57 | Pit |
54 | 58 | perl |
0 | ||
1 | BEGIN { | |
2 | unless ($ENV{AUTHOR_TESTING}) { | |
3 | require Test::More; | |
4 | Test::More::plan(skip_all => 'these tests are for testing by the author'); | |
5 | } | |
6 | } | |
7 | ||
8 | BEGIN { | |
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | ||
15 | use File::Spec; | |
16 | use lib File::Spec->catdir( 't', 'lib' ); | |
17 | ||
18 | use PVTests::Standard; | |
19 | PVTests::Standard::run_tests(); |
0 | ||
1 | BEGIN { | |
2 | unless ($ENV{AUTHOR_TESTING}) { | |
3 | require Test::More; | |
4 | Test::More::plan(skip_all => 'these tests are for testing by the author'); | |
5 | } | |
6 | } | |
7 | ||
8 | BEGIN { | |
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | ||
15 | use File::Spec; | |
16 | use lib File::Spec->catdir( 't', 'lib' ); | |
17 | ||
18 | BEGIN { $ENV{PERL_NO_VALIDATION} = 1 } | |
19 | ||
20 | use PVTests::Standard; | |
21 | PVTests::Standard::run_tests(); |
0 | ||
1 | BEGIN { | |
2 | unless ($ENV{AUTHOR_TESTING}) { | |
3 | require Test::More; | |
4 | Test::More::plan(skip_all => 'these tests are for testing by the author'); | |
5 | } | |
6 | } | |
7 | ||
8 | BEGIN { | |
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | ||
15 | use File::Spec; | |
16 | use lib File::Spec->catdir( 't', 'lib' ); | |
17 | ||
18 | use PVTests::Defaults; | |
19 | PVTests::Defaults::run_tests(); |
0 | ||
1 | BEGIN { | |
2 | unless ($ENV{AUTHOR_TESTING}) { | |
3 | require Test::More; | |
4 | Test::More::plan(skip_all => 'these tests are for testing by the author'); | |
5 | } | |
6 | } | |
7 | ||
8 | BEGIN { | |
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | ||
15 | use File::Spec; | |
16 | use lib File::Spec->catdir( 't', 'lib' ); | |
17 | ||
18 | BEGIN { $ENV{PERL_NO_VALIDATION} = 1 } | |
19 | ||
20 | use PVTests::Defaults; | |
21 | PVTests::Defaults::run_tests(); |
0 | ||
1 | BEGIN { | |
2 | unless ($ENV{AUTHOR_TESTING}) { | |
3 | require Test::More; | |
4 | Test::More::plan(skip_all => 'these tests are for testing by the author'); | |
5 | } | |
6 | } | |
7 | ||
8 | BEGIN { | |
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | ||
15 | use File::Spec; | |
16 | use lib File::Spec->catdir( 't', 'lib' ); | |
17 | ||
18 | use PVTests; | |
19 | use Test::More; | |
20 | ||
21 | use Params::Validate qw(:all); | |
22 | ||
23 | validation_options( stack_skip => 2 ); | |
24 | ||
25 | sub foo { | |
26 | my %p = validate( @_, { bar => 1 } ); | |
27 | } | |
28 | ||
29 | sub bar { foo(@_) } | |
30 | ||
31 | sub baz { bar(@_) } | |
32 | ||
33 | eval { baz() }; | |
34 | ||
35 | like( $@, qr/mandatory.*missing.*call to main::bar/i ); | |
36 | ||
37 | validation_options( stack_skip => 3 ); | |
38 | ||
39 | eval { baz() }; | |
40 | like( $@, qr/mandatory.*missing.*call to main::baz/i ); | |
41 | ||
42 | validation_options( on_fail => sub { die bless { hash => 'ref' }, 'Dead' } ); | |
43 | ||
44 | eval { baz() }; | |
45 | ||
46 | my $e = $@; | |
47 | is( $e->{hash}, 'ref' ); | |
48 | ok( eval { $e->isa('Dead'); 1; } ); | |
49 | ||
50 | done_testing(); |
0 | ||
1 | BEGIN { | |
2 | unless ($ENV{AUTHOR_TESTING}) { | |
3 | require Test::More; | |
4 | Test::More::plan(skip_all => 'these tests are for testing by the author'); | |
5 | } | |
6 | } | |
7 | ||
8 | BEGIN { | |
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | ||
15 | use File::Spec; | |
16 | use lib File::Spec->catdir( 't', 'lib' ); | |
17 | ||
18 | use PVTests::With; | |
19 | PVTests::With::run_tests(); |
0 | ||
1 | BEGIN { | |
2 | unless ($ENV{AUTHOR_TESTING}) { | |
3 | require Test::More; | |
4 | Test::More::plan(skip_all => 'these tests are for testing by the author'); | |
5 | } | |
6 | } | |
7 | ||
8 | BEGIN { | |
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | ||
15 | use File::Spec; | |
16 | use lib File::Spec->catdir( 't', 'lib' ); | |
17 | ||
18 | BEGIN { $ENV{PERL_NO_VALIDATION} = 1 } | |
19 | ||
20 | use PVTests::With; | |
21 | PVTests::With::run_tests(); |
0 | ||
1 | BEGIN { | |
2 | unless ($ENV{AUTHOR_TESTING}) { | |
3 | require Test::More; | |
4 | Test::More::plan(skip_all => 'these tests are for testing by the author'); | |
5 | } | |
6 | } | |
7 | ||
8 | BEGIN { | |
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | ||
15 | use File::Spec; | |
16 | use lib File::Spec->catdir( 't', 'lib' ); | |
17 | ||
18 | use PVTests::Regex; | |
19 | PVTests::Regex::run_tests(); |
0 | ||
1 | BEGIN { | |
2 | unless ($ENV{AUTHOR_TESTING}) { | |
3 | require Test::More; | |
4 | Test::More::plan(skip_all => 'these tests are for testing by the author'); | |
5 | } | |
6 | } | |
7 | ||
8 | BEGIN { | |
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | ||
15 | use File::Spec; | |
16 | use lib File::Spec->catdir( 't', 'lib' ); | |
17 | ||
18 | BEGIN { $ENV{PERL_NO_VALIDATION} = 1 } | |
19 | ||
20 | use PVTests::Regex; | |
21 | PVTests::Regex::run_tests(); |
0 | ||
1 | BEGIN { | |
2 | unless ($ENV{AUTHOR_TESTING}) { | |
3 | require Test::More; | |
4 | Test::More::plan(skip_all => 'these tests are for testing by the author'); | |
5 | } | |
6 | } | |
7 | ||
8 | BEGIN { | |
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | ||
15 | use File::Spec; | |
16 | use lib File::Spec->catdir( 't', 'lib' ); | |
17 | ||
18 | use PVTests::Callbacks; | |
19 | PVTests::Callbacks::run_tests(); |
0 | ||
1 | BEGIN { | |
2 | unless ($ENV{AUTHOR_TESTING}) { | |
3 | require Test::More; | |
4 | Test::More::plan(skip_all => 'these tests are for testing by the author'); | |
5 | } | |
6 | } | |
7 | ||
8 | BEGIN { | |
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | ||
15 | use File::Spec; | |
16 | use lib File::Spec->catdir( 't', 'lib' ); | |
17 | ||
18 | BEGIN { $ENV{PERL_NO_VALIDATION} = 1 } | |
19 | ||
20 | use PVTests::Callbacks; | |
21 | PVTests::Callbacks::run_tests(); |
0 | ||
1 | BEGIN { | |
2 | unless ($ENV{AUTHOR_TESTING}) { | |
3 | require Test::More; | |
4 | Test::More::plan(skip_all => 'these tests are for testing by the author'); | |
5 | } | |
6 | } | |
7 | ||
8 | BEGIN { | |
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | ||
15 | use File::Spec; | |
16 | use lib File::Spec->catdir( 't', 'lib' ); | |
17 | ||
18 | eval { "$0$^X" && kill 0; 1 }; | |
19 | ||
20 | use PVTests::Standard; | |
21 | PVTests::Standard::run_tests(); |
0 | ||
1 | BEGIN { | |
2 | unless ($ENV{AUTHOR_TESTING}) { | |
3 | require Test::More; | |
4 | Test::More::plan(skip_all => 'these tests are for testing by the author'); | |
5 | } | |
6 | } | |
7 | ||
8 | BEGIN { | |
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | ||
15 | use lib './t'; | |
16 | ||
17 | use Params::Validate qw(validate); | |
18 | ||
19 | use Test::More; | |
20 | plan tests => $] == 5.006 ? 2 : 3; | |
21 | ||
22 | eval { foo() }; | |
23 | like( $@, qr/parameter 'foo'/ ); | |
24 | ||
25 | { | |
26 | local $Params::Validate::NO_VALIDATION = 1; | |
27 | ||
28 | eval { foo() }; | |
29 | is( $@, q{} ); | |
30 | } | |
31 | ||
32 | unless ( $] == 5.006 ) { | |
33 | eval { foo() }; | |
34 | like( $@, qr/parameter 'foo'/ ); | |
35 | } | |
36 | ||
37 | sub foo { | |
38 | validate( @_, { foo => 1 } ); | |
39 | } |
0 | ||
1 | BEGIN { | |
2 | unless ($ENV{AUTHOR_TESTING}) { | |
3 | require Test::More; | |
4 | Test::More::plan(skip_all => 'these tests are for testing by the author'); | |
5 | } | |
6 | } | |
7 | ||
8 | BEGIN { | |
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | ||
15 | use Test::More; | |
16 | ||
17 | use Params::Validate qw(validate validate_with); | |
18 | ||
19 | my @testset; | |
20 | ||
21 | # Generate test cases ... | |
22 | BEGIN { | |
23 | my @lower_case_args = ( foo => 1 ); | |
24 | my @upper_case_args = ( FOO => 1 ); | |
25 | my @mixed_case_args = ( FoO => 1 ); | |
26 | ||
27 | my %lower_case_spec = ( foo => 1 ); | |
28 | my %upper_case_spec = ( FOO => 1 ); | |
29 | my %mixed_case_spec = ( FoO => 1 ); | |
30 | ||
31 | my %arglist = ( | |
32 | lower => \@lower_case_args, | |
33 | upper => \@upper_case_args, | |
34 | mixed => \@mixed_case_args | |
35 | ); | |
36 | ||
37 | my %speclist = ( | |
38 | lower => \%lower_case_spec, | |
39 | upper => \%upper_case_spec, | |
40 | mixed => \%mixed_case_spec | |
41 | ); | |
42 | ||
43 | # XXX - make subs such that user gets to see the error message | |
44 | # when a test fails | |
45 | my $ok_sub = sub { | |
46 | if ($@) { | |
47 | print STDERR $@; | |
48 | } | |
49 | !$@; | |
50 | }; | |
51 | ||
52 | my $nok_sub = sub { | |
53 | my $ok = ( $@ =~ /not listed in the validation options/ ); | |
54 | unless ($ok) { | |
55 | print STDERR $@; | |
56 | } | |
57 | $ok; | |
58 | }; | |
59 | ||
60 | # generate testcases on the fly (I'm too lazy) | |
61 | for my $ignore_case (qw( 0 1 )) { | |
62 | for my $args ( keys %arglist ) { | |
63 | for my $spec ( keys %speclist ) { | |
64 | push @testset, { | |
65 | params => $arglist{$args}, | |
66 | spec => $speclist{$spec}, | |
67 | expect => ( | |
68 | $ignore_case ? $ok_sub | |
69 | : $args eq $spec ? $ok_sub | |
70 | : $nok_sub | |
71 | ), | |
72 | ignore_case => $ignore_case | |
73 | }; | |
74 | } | |
75 | } | |
76 | } | |
77 | } | |
78 | ||
79 | plan tests => ( scalar @testset ) * 2; | |
80 | ||
81 | { | |
82 | ||
83 | # XXX - "called" will be all messed up, but what the heck | |
84 | foreach my $case (@testset) { | |
85 | my %args = eval { | |
86 | validate_with( | |
87 | params => $case->{params}, | |
88 | spec => $case->{spec}, | |
89 | ignore_case => $case->{ignore_case} | |
90 | ); | |
91 | }; | |
92 | ||
93 | ok( $case->{expect}->(%args) ); | |
94 | } | |
95 | ||
96 | # XXX - make sure that it works from validation_options() as well | |
97 | foreach my $case (@testset) { | |
98 | Params::Validate::validation_options( | |
99 | ignore_case => $case->{ignore_case} ); | |
100 | ||
101 | my %args = eval { | |
102 | my @args = @{ $case->{params} }; | |
103 | validate( @args, $case->{spec} ); | |
104 | }; | |
105 | ||
106 | ok( $case->{expect}->(%args) ); | |
107 | } | |
108 | } |
0 | ||
1 | BEGIN { | |
2 | unless ($ENV{AUTHOR_TESTING}) { | |
3 | require Test::More; | |
4 | Test::More::plan(skip_all => 'these tests are for testing by the author'); | |
5 | } | |
6 | } | |
7 | ||
8 | BEGIN { | |
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | ||
15 | use Params::Validate qw(validate validate_with); | |
16 | use Test::More; | |
17 | ||
18 | my $ucfirst_normalizer = sub { return ucfirst lc $_[0] }; | |
19 | ||
20 | sub sub1 { | |
21 | my %args = validate_with( | |
22 | params => \@_, | |
23 | spec => { PaRaMkEy => 1 }, | |
24 | normalize_keys => $ucfirst_normalizer | |
25 | ); | |
26 | ||
27 | return $args{Paramkey}; | |
28 | } | |
29 | ||
30 | sub sub2 { | |
31 | ||
32 | # verify that normalize_callback surpresses ignore_case | |
33 | my %args = validate_with( | |
34 | params => \@_, | |
35 | spec => { PaRaMkEy => 1 }, | |
36 | normalize_keys => $ucfirst_normalizer, | |
37 | ignore_case => 1 | |
38 | ); | |
39 | ||
40 | return $args{Paramkey}; | |
41 | } | |
42 | ||
43 | sub sub3 { | |
44 | ||
45 | # verify that normalize_callback surpresses strip_leading | |
46 | my %args = validate_with( | |
47 | params => \@_, | |
48 | spec => { -PaRaMkEy => 1 }, | |
49 | normalize_keys => $ucfirst_normalizer, | |
50 | strip_leading => '-' | |
51 | ); | |
52 | ||
53 | return $args{-paramkey}; | |
54 | } | |
55 | ||
56 | sub sub4 { | |
57 | my %args = validate_with( | |
58 | params => \@_, | |
59 | spec => { foo => 1 }, | |
60 | normalize_keys => sub {undef} | |
61 | ); | |
62 | } | |
63 | ||
64 | sub sub5 { | |
65 | my %args = validate_with( | |
66 | params => \@_, | |
67 | spec => { foo => 1 }, | |
68 | normalize_keys => sub { return 'a' }, | |
69 | ); | |
70 | } | |
71 | ||
72 | ok( eval { sub1( pArAmKeY => 1 ) } ); | |
73 | ok( eval { sub2( pArAmKeY => 1 ) } ); | |
74 | ok( eval { sub3( -pArAmKeY => 1 ) } ); | |
75 | ||
76 | eval { sub4( foo => 5 ) }; | |
77 | like( $@, qr/normalize_keys.+a defined value/ ); | |
78 | ||
79 | eval { sub5( foo => 5, bar => 5 ) }; | |
80 | like( $@, qr/normalize_keys.+already exists/ ); | |
81 | ||
82 | done_testing(); |
0 | ||
1 | BEGIN { | |
2 | unless ($ENV{AUTHOR_TESTING}) { | |
3 | require Test::More; | |
4 | Test::More::plan(skip_all => 'these tests are for testing by the author'); | |
5 | } | |
6 | } | |
7 | ||
8 | BEGIN { | |
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | ||
15 | use Params::Validate qw(validate validate_pos SCALAR); | |
16 | use Test::More; | |
17 | ||
18 | { | |
19 | my @p = ( foo => 1, bar => 2 ); | |
20 | ||
21 | eval { | |
22 | validate( | |
23 | @p, { | |
24 | foo => { | |
25 | type => SCALAR, | |
26 | callbacks => { | |
27 | 'bigger than bar' => sub { $_[0] > $_[1]->{bar} } | |
28 | }, | |
29 | }, | |
30 | bar => { type => SCALAR }, | |
31 | } | |
32 | ); | |
33 | }; | |
34 | ||
35 | like( $@, qr/bigger than bar/ ); | |
36 | ||
37 | $p[1] = 3; | |
38 | eval { | |
39 | validate( | |
40 | @p, { | |
41 | foo => { | |
42 | type => SCALAR, | |
43 | callbacks => { | |
44 | 'bigger than bar' => sub { $_[0] > $_[1]->{bar} } | |
45 | }, | |
46 | }, | |
47 | bar => { type => SCALAR }, | |
48 | } | |
49 | ); | |
50 | }; | |
51 | ||
52 | is( $@, q{} ); | |
53 | } | |
54 | ||
55 | { | |
56 | my @p = ( 1, 2, 3 ); | |
57 | eval { | |
58 | validate_pos( | |
59 | @p, { | |
60 | type => SCALAR, | |
61 | callbacks => { | |
62 | 'bigger than [1]' => sub { $_[0] > $_[1]->[1] } | |
63 | } | |
64 | }, | |
65 | { type => SCALAR }, | |
66 | { type => SCALAR }, | |
67 | ); | |
68 | }; | |
69 | ||
70 | like( $@, qr/bigger than \[1\]/ ); | |
71 | ||
72 | $p[0] = 5; | |
73 | eval { | |
74 | validate_pos( | |
75 | @p, { | |
76 | type => SCALAR, | |
77 | callbacks => { | |
78 | 'bigger than [1]' => sub { $_[0] > $_[1]->[1] } | |
79 | } | |
80 | }, | |
81 | { type => SCALAR }, | |
82 | { type => SCALAR }, | |
83 | ); | |
84 | }; | |
85 | ||
86 | is( $@, q{} ); | |
87 | } | |
88 | ||
89 | done_testing(); |
0 | ||
1 | BEGIN { | |
2 | unless ($ENV{AUTHOR_TESTING}) { | |
3 | require Test::More; | |
4 | Test::More::plan(skip_all => 'these tests are for testing by the author'); | |
5 | } | |
6 | } | |
7 | ||
8 | BEGIN { | |
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | ||
15 | use Params::Validate qw(validate validate_pos); | |
16 | use Test::More; | |
17 | ||
18 | { | |
19 | my %spec = ( | |
20 | foo => { optional => 1, depends => 'bar' }, | |
21 | bar => { optional => 1 }, | |
22 | ); | |
23 | ||
24 | my @args = ( bar => 1 ); | |
25 | ||
26 | eval { validate( @args, \%spec ) }; | |
27 | ||
28 | is( $@, q{}, "validate() single depends(1): no depends, positive" ); | |
29 | ||
30 | @args = ( foo => 1, bar => 1 ); | |
31 | eval { validate( @args, \%spec ) }; | |
32 | ||
33 | is( $@, q{}, "validate() single depends(2): with depends, positive" ); | |
34 | ||
35 | @args = ( foo => 1 ); | |
36 | eval { validate( @args, \%spec ) }; | |
37 | ||
38 | ok( $@, "validate() single depends(3.a): with depends, negative" ); | |
39 | like( | |
40 | $@, | |
41 | qr(^Parameter 'foo' depends on parameter 'bar', which was not given), | |
42 | "validate() single depends(3.b): check error string" | |
43 | ); | |
44 | } | |
45 | ||
46 | { | |
47 | my %spec = ( | |
48 | foo => { optional => 1, depends => [qw(bar baz)] }, | |
49 | bar => { optional => 1 }, | |
50 | baz => { optional => 1 }, | |
51 | ); | |
52 | ||
53 | # positive, no depends (single, multiple) | |
54 | my @args = ( bar => 1 ); | |
55 | eval { validate( @args, \%spec ) }; | |
56 | is( | |
57 | $@, q{}, | |
58 | "validate() multiple depends(1): no depends, single arg, positive" | |
59 | ); | |
60 | ||
61 | @args = ( bar => 1, baz => 1 ); | |
62 | eval { validate( @args, \%spec ) }; | |
63 | ||
64 | is( | |
65 | $@, q{}, | |
66 | "validate() multiple depends(2): no depends, multiple arg, positive" | |
67 | ); | |
68 | ||
69 | @args = ( foo => 1, bar => 1, baz => 1 ); | |
70 | eval { validate( @args, \%spec ) }; | |
71 | ||
72 | is( $@, q{}, "validate() multiple depends(3): with depends, positive" ); | |
73 | ||
74 | @args = ( foo => 1, bar => 1 ); | |
75 | eval { validate( @args, \%spec ) }; | |
76 | ||
77 | ok( | |
78 | $@, | |
79 | "validate() multiple depends(4.a): with depends, negative, multiple missing" | |
80 | ); | |
81 | like( | |
82 | $@, | |
83 | qr(^Parameter 'foo' depends on parameter 'baz', which was not given), | |
84 | "validate() multiple depends (4.b): check error string" | |
85 | ); | |
86 | ||
87 | @args = ( foo => 1 ); | |
88 | eval { validate( @args, \%spec ) }; | |
89 | ||
90 | ok( | |
91 | $@, | |
92 | "validate() multiple depends(5.a): with depends, negative, multiple missing" | |
93 | ); | |
94 | like( | |
95 | $@, | |
96 | qr(^Parameter 'foo' depends on parameter '(bar|baz)', which was not given), | |
97 | "validate() multiple depends (5.b): check error string" | |
98 | ); | |
99 | } | |
100 | ||
101 | { | |
102 | ||
103 | # bad depends | |
104 | my %spec = ( | |
105 | foo => { optional => 1, depends => { 'bar' => 1 } }, | |
106 | bar => { optional => 1 }, | |
107 | ); | |
108 | ||
109 | my @args = ( foo => 1 ); | |
110 | eval { validate( @args, \%spec ) }; | |
111 | ||
112 | ok( $@, "validate() bad depends spec (1.a): depends is a hashref" ); | |
113 | like( | |
114 | $@, | |
115 | qr(^Arguments to 'depends' must be a scalar or arrayref), | |
116 | "validate() bad depends spec (1.a): check error string" | |
117 | ); | |
118 | } | |
119 | ||
120 | { | |
121 | my @spec = ( { optional => 1 } ); | |
122 | ||
123 | my @args = qw(1); | |
124 | eval { validate_pos( @args, @spec ) }; | |
125 | ||
126 | is( $@, q{}, "validate_pos() no depends, positive" ); | |
127 | } | |
128 | ||
129 | { | |
130 | my @spec = ( { optional => 1, depends => 2 }, { optional => 1 } ); | |
131 | ||
132 | my @args = qw(1 1); | |
133 | eval { validate_pos( @args, @spec ) }; | |
134 | ||
135 | is( | |
136 | $@, q{}, | |
137 | "validate_pos() single depends (1): with depends, positive" | |
138 | ); | |
139 | } | |
140 | ||
141 | { | |
142 | my @spec = ( | |
143 | { optional => 1, depends => 4 }, | |
144 | { optional => 1 }, { optional => 1 }, | |
145 | { optional => 1 } | |
146 | ); | |
147 | ||
148 | my @args = qw(1 0); | |
149 | eval { validate_pos( @args, @spec ) }; | |
150 | ||
151 | ok( $@, "validate_pos() single depends (2.a): with depends, negative" ); | |
152 | like( | |
153 | $@, | |
154 | qr(^Parameter #1 depends on parameter #4, which was not given), | |
155 | "validate_pos() single depends (2.b): check error" | |
156 | ); | |
157 | } | |
158 | ||
159 | { | |
160 | my @spec = ( | |
161 | { optional => 1, depends => [ 2, 3 ] }, | |
162 | { optional => 1 }, | |
163 | 0 | |
164 | ); | |
165 | my @args = qw(1); | |
166 | eval { validate_pos( @args, @spec ) }; | |
167 | ||
168 | ok( | |
169 | $@, | |
170 | "validate_pos() multiple depends (1.a): with depends, bad args negative" | |
171 | ); | |
172 | like( | |
173 | $@, | |
174 | qr{^Arguments to 'depends' for validate_pos\(\) must be a scalar}, | |
175 | "validate_pos() multiple depends (1.b): check error" | |
176 | ); | |
177 | } | |
178 | ||
179 | done_testing(); |
0 | #!/usr/bin/perl -T | |
1 | ||
2 | BEGIN { | |
3 | unless ($ENV{AUTHOR_TESTING}) { | |
4 | require Test::More; | |
5 | Test::More::plan(skip_all => 'these tests are for testing by the author'); | |
6 | } | |
7 | } | |
8 | ||
9 | ||
10 | BEGIN { | |
11 | $ENV{PV_TEST_PERL} = 1; | |
12 | } | |
13 | ||
14 | ||
15 | use strict; | |
16 | use warnings; | |
17 | ||
18 | use Test::Requires { | |
19 | 'Test::Taint' => 0.02, | |
20 | }; | |
21 | ||
22 | use Params::Validate qw(validate validate_pos); | |
23 | use Test::More; | |
24 | ||
25 | taint_checking_ok('These tests are meaningless unless we are in taint mode.'); | |
26 | ||
27 | { | |
28 | my $value = 7; | |
29 | taint($value); | |
30 | ||
31 | tainted_ok( $value, 'make sure $value is tainted' ); | |
32 | ||
33 | my @p = ( value => $value ); | |
34 | my %p = validate( | |
35 | @p, { | |
36 | value => { | |
37 | regex => qr/^\d+$/, | |
38 | untaint => 1, | |
39 | }, | |
40 | }, | |
41 | ); | |
42 | ||
43 | untainted_ok( $p{value}, 'value is untainted after validation' ); | |
44 | } | |
45 | ||
46 | { | |
47 | my $value = 'foo'; | |
48 | ||
49 | taint($value); | |
50 | ||
51 | tainted_ok( $value, 'make sure $value is tainted' ); | |
52 | ||
53 | my @p = ($value); | |
54 | my ($new_value) = validate_pos( | |
55 | @p, { | |
56 | regex => qr/foo/, | |
57 | untaint => 1, | |
58 | }, | |
59 | ); | |
60 | ||
61 | untainted_ok( $new_value, 'value is untainted after validation' ); | |
62 | } | |
63 | ||
64 | { | |
65 | my $value = 7; | |
66 | taint($value); | |
67 | ||
68 | tainted_ok( $value, 'make sure $value is tainted' ); | |
69 | ||
70 | my @p = ( value => $value ); | |
71 | my %p = validate( | |
72 | @p, { | |
73 | value => { | |
74 | regex => qr/^\d+$/, | |
75 | }, | |
76 | }, | |
77 | ); | |
78 | ||
79 | tainted_ok( $p{value}, 'value is still tainted after validation' ); | |
80 | } | |
81 | ||
82 | { | |
83 | my $value = 'foo'; | |
84 | ||
85 | taint($value); | |
86 | ||
87 | tainted_ok( $value, 'make sure $value is tainted' ); | |
88 | ||
89 | my @p = ($value); | |
90 | my ($new_value) = validate_pos( | |
91 | @p, { | |
92 | regex => qr/foo/, | |
93 | }, | |
94 | ); | |
95 | ||
96 | tainted_ok( $new_value, 'value is still tainted after validation' ); | |
97 | } | |
98 | ||
99 | done_testing(); |
0 | ||
1 | BEGIN { | |
2 | unless ($ENV{AUTHOR_TESTING}) { | |
3 | require Test::More; | |
4 | Test::More::plan(skip_all => 'these tests are for testing by the author'); | |
5 | } | |
6 | } | |
7 | ||
8 | BEGIN { | |
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | ||
15 | use Params::Validate qw(validate); | |
16 | use Test::More; | |
17 | ||
18 | { | |
19 | my @p = ( foo => 'ClassCan' ); | |
20 | ||
21 | eval { validate( @p, { foo => { can => 'cancan' } }, ); }; | |
22 | ||
23 | is( $@, q{} ); | |
24 | ||
25 | eval { validate( @p, { foo => { can => 'thingy' } }, ); }; | |
26 | ||
27 | like( $@, qr/does not have the method: 'thingy'/ ); | |
28 | } | |
29 | ||
30 | { | |
31 | my @p = ( foo => undef ); | |
32 | eval { validate( @p, { foo => { can => 'baz' } }, ); }; | |
33 | ||
34 | like( $@, qr/does not have the method: 'baz'/ ); | |
35 | } | |
36 | ||
37 | { | |
38 | my $object = bless {}, 'ClassCan'; | |
39 | my @p = ( foo => $object ); | |
40 | ||
41 | eval { validate( @p, { foo => { can => 'cancan' } }, ); }; | |
42 | ||
43 | is( $@, q{} ); | |
44 | ||
45 | eval { validate( @p, { foo => { can => 'thingy' } }, ); }; | |
46 | ||
47 | like( $@, qr/does not have the method: 'thingy'/ ); | |
48 | } | |
49 | ||
50 | { | |
51 | my @p = ( foo => 'SubClass' ); | |
52 | ||
53 | eval { validate( @p, { foo => { can => 'cancan' } }, ); }; | |
54 | ||
55 | is( $@, q{}, 'SubClass->can(cancan)' ); | |
56 | ||
57 | eval { validate( @p, { foo => { can => 'thingy' } }, ); }; | |
58 | ||
59 | like( $@, qr/does not have the method: 'thingy'/ ); | |
60 | } | |
61 | ||
62 | { | |
63 | my $object = bless {}, 'SubClass'; | |
64 | my @p = ( foo => $object ); | |
65 | ||
66 | eval { validate( @p, { foo => { can => 'cancan' } }, ); }; | |
67 | ||
68 | is( $@, q{}, 'SubClass object->can(cancan)' ); | |
69 | ||
70 | eval { validate( @p, { foo => { can => 'thingy' } }, ); }; | |
71 | ||
72 | like( $@, qr/does not have the method: 'thingy'/ ); | |
73 | } | |
74 | ||
75 | { | |
76 | my @p = ( foo => {} ); | |
77 | eval { validate( @p, { foo => { can => 'thingy' } }, ); }; | |
78 | like( $@, qr/does not have the method: 'thingy'/, 'unblessed ref ->can' ); | |
79 | ||
80 | @p = ( foo => 27 ); | |
81 | eval { validate( @p, { foo => { can => 'thingy' } }, ); }; | |
82 | like( $@, qr/does not have the method: 'thingy'/, 'number can' ); | |
83 | ||
84 | @p = ( foo => 'A String' ); | |
85 | eval { validate( @p, { foo => { can => 'thingy' } }, ); }; | |
86 | like( $@, qr/does not have the method: 'thingy'/, 'string can' ); | |
87 | ||
88 | @p = ( foo => undef ); | |
89 | eval { validate( @p, { foo => { can => 'thingy' } }, ); }; | |
90 | like( $@, qr/does not have the method: 'thingy'/, 'undef can' ); | |
91 | } | |
92 | ||
93 | done_testing(); | |
94 | ||
95 | package ClassCan; | |
96 | ||
97 | sub can { | |
98 | return 1 if $_[1] eq 'cancan'; | |
99 | return 0; | |
100 | } | |
101 | ||
102 | sub thingy {1} | |
103 | ||
104 | package SubClass; | |
105 | ||
106 | use base 'ClassCan'; |
0 | ||
1 | BEGIN { | |
2 | unless ($ENV{AUTHOR_TESTING}) { | |
3 | require Test::More; | |
4 | Test::More::plan(skip_all => 'these tests are for testing by the author'); | |
5 | } | |
6 | } | |
7 | ||
8 | BEGIN { | |
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | ||
15 | use Params::Validate qw(validate); | |
16 | use Test::More; | |
17 | ||
18 | { | |
19 | package Overloaded; | |
20 | ||
21 | use overload 'bool' => sub {0}; | |
22 | ||
23 | sub new { bless {} } | |
24 | ||
25 | sub foo {1} | |
26 | } | |
27 | ||
28 | my $ovl = Overloaded->new; | |
29 | ||
30 | { | |
31 | eval { | |
32 | my @p = ( object => $ovl ); | |
33 | validate( @p, { object => { isa => 'Overloaded' } } ); | |
34 | }; | |
35 | ||
36 | is( $@, q{}, 'overloaded object->isa' ); | |
37 | } | |
38 | ||
39 | { | |
40 | eval { | |
41 | my @p = ( object => $ovl ); | |
42 | validate( @p, { object => { can => 'foo' } } ); | |
43 | }; | |
44 | ||
45 | is( $@, q{}, 'overloaded object->foo' ); | |
46 | } | |
47 | ||
48 | done_testing(); |
0 | ||
1 | BEGIN { | |
2 | unless ($ENV{AUTHOR_TESTING}) { | |
3 | require Test::More; | |
4 | Test::More::plan(skip_all => 'these tests are for testing by the author'); | |
5 | } | |
6 | } | |
7 | ||
8 | BEGIN { | |
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | ||
15 | use Test::Requires { | |
16 | Readonly => '1.03', | |
17 | 'Scalar::Util' => '1.20', | |
18 | }; | |
19 | ||
20 | use Params::Validate qw(validate validate_pos SCALAR); | |
21 | use Test::More; | |
22 | ||
23 | plan skip_all => 'These tests fail with Readonly 1.50 for some reason' | |
24 | if Readonly::->VERSION() =~ /^v?1.5/; | |
25 | ||
26 | { | |
27 | Readonly my $spec => { foo => 1 }; | |
28 | my @p = ( foo => 'hello' ); | |
29 | ||
30 | eval { validate( @p, $spec ) }; | |
31 | is( $@, q{}, 'validate() call succeeded with Readonly spec hashref' ); | |
32 | } | |
33 | ||
34 | { | |
35 | Readonly my $spec => { type => SCALAR }; | |
36 | my @p = 'hello'; | |
37 | ||
38 | eval { validate_pos( @p, $spec ) }; | |
39 | is( $@, q{}, 'validate_pos() call succeeded with Readonly spec hashref' ); | |
40 | } | |
41 | ||
42 | { | |
43 | Readonly my %spec => ( foo => { type => SCALAR } ); | |
44 | my @p = ( foo => 'hello' ); | |
45 | ||
46 | eval { validate( @p, \%spec ) }; | |
47 | is( $@, q{}, 'validate() call succeeded with Readonly spec hash' ); | |
48 | } | |
49 | ||
50 | done_testing(); |
0 | ||
1 | BEGIN { | |
2 | unless ($ENV{AUTHOR_TESTING}) { | |
3 | require Test::More; | |
4 | Test::More::plan(skip_all => 'these tests are for testing by the author'); | |
5 | } | |
6 | } | |
7 | ||
8 | BEGIN { | |
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | ||
15 | use Params::Validate qw(validate validate_pos SCALAR); | |
16 | use Test::More; | |
17 | ||
18 | { | |
19 | package Tie::SimpleArray; | |
20 | use Tie::Array; | |
21 | use base 'Tie::StdArray'; | |
22 | } | |
23 | ||
24 | { | |
25 | ||
26 | package Tie::SimpleHash; | |
27 | use Tie::Hash; | |
28 | use base 'Tie::StdHash'; | |
29 | } | |
30 | ||
31 | { | |
32 | tie my @p, 'Tie::SimpleArray'; | |
33 | ||
34 | my %spec = ( foo => 1 ); | |
35 | push @p, ( foo => 'hello' ); | |
36 | ||
37 | eval { validate( @p, \%spec ) }; | |
38 | warn $@ if $@; | |
39 | is( | |
40 | $@, q{}, | |
41 | 'validate() call succeeded with tied params array and regular hashref spec' | |
42 | ); | |
43 | } | |
44 | ||
45 | SKIP: | |
46 | { | |
47 | skip 'Params::Validate segfaults with tied hash for spec', 1; | |
48 | ||
49 | my @p; | |
50 | tie my %spec, 'Tie::SimpleHash'; | |
51 | ||
52 | $spec{foo} = 1; | |
53 | push @p, ( foo => 'hello' ); | |
54 | ||
55 | eval { validate( @p, \%spec ) }; | |
56 | warn $@ if $@; | |
57 | is( | |
58 | $@, q{}, | |
59 | 'validate() call succeeded with regular params array and tied hashref spec' | |
60 | ); | |
61 | } | |
62 | ||
63 | SKIP: | |
64 | { | |
65 | skip 'Params::Validate segfaults with tied hash for spec', 1; | |
66 | ||
67 | tie my @p, 'Tie::SimpleArray'; | |
68 | tie my %spec, 'Tie::SimpleHash'; | |
69 | ||
70 | $spec{foo} = 1; | |
71 | push @p, ( foo => 'hello' ); | |
72 | ||
73 | eval { validate( @p, \%spec ) }; | |
74 | warn $@ if $@; | |
75 | is( | |
76 | $@, q{}, | |
77 | 'validate() call succeeded with tied params array and tied hashref spec' | |
78 | ); | |
79 | } | |
80 | ||
81 | { | |
82 | tie my @p, 'Tie::SimpleArray'; | |
83 | my %spec; | |
84 | ||
85 | $spec{type} = SCALAR; | |
86 | push @p, 'hello'; | |
87 | ||
88 | eval { validate_pos( @p, \%spec ) }; | |
89 | warn $@ if $@; | |
90 | is( | |
91 | $@, q{}, | |
92 | 'validate_pos() call succeeded with tied params array and regular hashref spec' | |
93 | ); | |
94 | } | |
95 | ||
96 | SKIP: | |
97 | { | |
98 | skip 'Params::Validate segfaults with tied hash for spec', 1; | |
99 | ||
100 | my @p; | |
101 | tie my %spec, 'Tie::SimpleHash'; | |
102 | ||
103 | $spec{type} = SCALAR; | |
104 | push @p, 'hello'; | |
105 | ||
106 | eval { validate_pos( @p, \%spec ) }; | |
107 | warn $@ if $@; | |
108 | is( | |
109 | $@, q{}, | |
110 | 'validate_pos() call succeeded with regular params array and tied hashref spec' | |
111 | ); | |
112 | } | |
113 | ||
114 | SKIP: | |
115 | { | |
116 | skip 'Params::Validate segfaults with tied hash for spec', 1; | |
117 | ||
118 | tie my @p, 'Tie::SimpleArray'; | |
119 | tie my %spec, 'Tie::SimpleHash'; | |
120 | ||
121 | $spec{type} = SCALAR; | |
122 | push @p, 'hello'; | |
123 | ||
124 | eval { validate_pos( @p, \%spec ) }; | |
125 | warn $@ if $@; | |
126 | is( | |
127 | $@, q{}, | |
128 | 'validate_pos() call succeeded with tied params array and tied hashref spec' | |
129 | ); | |
130 | } | |
131 | ||
132 | done_testing(); |
0 | ||
1 | BEGIN { | |
2 | unless ($ENV{AUTHOR_TESTING}) { | |
3 | require Test::More; | |
4 | Test::More::plan(skip_all => 'these tests are for testing by the author'); | |
5 | } | |
6 | } | |
7 | ||
8 | BEGIN { | |
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | ||
15 | use Params::Validate qw(validate); | |
16 | use Test::More; | |
17 | ||
18 | { | |
19 | my @w; | |
20 | local $SIG{__WARN__} = sub { push @w, @_ }; | |
21 | ||
22 | my @p = ( foo => undef ); | |
23 | eval { validate( @p, { foo => { regex => qr/^bar/ } } ) }; | |
24 | ok( $@, 'validation failed' ); | |
25 | ok( !@w, 'no warnings' ); | |
26 | } | |
27 | ||
28 | done_testing(); |
0 | ||
1 | BEGIN { | |
2 | unless ($ENV{AUTHOR_TESTING}) { | |
3 | require Test::More; | |
4 | Test::More::plan(skip_all => 'these tests are for testing by the author'); | |
5 | } | |
6 | } | |
7 | ||
8 | BEGIN { | |
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | ||
15 | use Params::Validate qw(validate); | |
16 | use Test::More; | |
17 | ||
18 | { | |
19 | my @p = ( foo => 'ClassISA' ); | |
20 | ||
21 | eval { validate( @p, { foo => { isa => 'FooBar' } }, ); }; | |
22 | ||
23 | is( $@, q{}, 'no error checking if ClassISA->isa(FooBar)' ); | |
24 | ||
25 | eval { validate( @p, { foo => { isa => 'Thingy' } }, ); }; | |
26 | ||
27 | like( $@, qr/was not a 'Thingy'/ ); | |
28 | } | |
29 | ||
30 | { | |
31 | my @p = ( foo => undef ); | |
32 | eval { validate( @p, { foo => { isa => 'FooBar' } }, ); }; | |
33 | ||
34 | like( $@, qr/was not a 'FooBar'/ ); | |
35 | } | |
36 | ||
37 | { | |
38 | my @p = ( foo => 'SubClass' ); | |
39 | ||
40 | eval { validate( @p, { foo => { isa => 'ClassISA' } }, ); }; | |
41 | ||
42 | is( $@, q{}, 'SubClass->isa(ClassISA)' ); | |
43 | ||
44 | eval { validate( @p, { foo => { isa => 'FooBar' } }, ); }; | |
45 | ||
46 | is( $@, q{}, 'SubClass->isa(FooBar)' ); | |
47 | ||
48 | eval { validate( @p, { foo => { isa => 'Thingy' } }, ); }; | |
49 | ||
50 | like( $@, qr/was not a 'Thingy'/ ); | |
51 | } | |
52 | ||
53 | { | |
54 | my @p = ( foo => bless {}, 'SubClass' ); | |
55 | ||
56 | eval { validate( @p, { foo => { isa => 'ClassISA' } }, ); }; | |
57 | ||
58 | is( $@, q{}, 'SubClass->isa(ClassISA)' ); | |
59 | ||
60 | eval { validate( @p, { foo => { isa => 'FooBar' } }, ); }; | |
61 | ||
62 | is( $@, q{}, 'SubClass->isa(FooBar)' ); | |
63 | ||
64 | eval { validate( @p, { foo => { isa => 'Thingy' } }, ); }; | |
65 | ||
66 | like( $@, qr/was not a 'Thingy'/ ); | |
67 | } | |
68 | ||
69 | { | |
70 | my @p = ( foo => {} ); | |
71 | eval { validate( @p, { foo => { isa => 'Thingy' } }, ); }; | |
72 | like( $@, qr/was not a 'Thingy'/, 'unblessed ref ->isa' ); | |
73 | ||
74 | @p = ( foo => 27 ); | |
75 | eval { validate( @p, { foo => { isa => 'Thingy' } }, ); }; | |
76 | like( $@, qr/was not a 'Thingy'/, 'number isa' ); | |
77 | ||
78 | @p = ( foo => 'A String' ); | |
79 | eval { validate( @p, { foo => { isa => 'Thingy' } }, ); }; | |
80 | like( $@, qr/was not a 'Thingy'/, 'string isa' ); | |
81 | ||
82 | @p = ( foo => undef ); | |
83 | eval { validate( @p, { foo => { isa => 'Thingy' } }, ); }; | |
84 | like( $@, qr/was not a 'Thingy'/, 'undef isa' ); | |
85 | } | |
86 | ||
87 | done_testing(); | |
88 | ||
89 | package ClassISA; | |
90 | ||
91 | sub isa { | |
92 | return 1 if $_[1] eq 'FooBar'; | |
93 | return $_[0]->SUPER::isa( $_[1] ); | |
94 | } | |
95 | ||
96 | sub thingy {1} | |
97 | ||
98 | package SubClass; | |
99 | ||
100 | use base 'ClassISA'; |
0 | ||
1 | BEGIN { | |
2 | unless ($ENV{AUTHOR_TESTING}) { | |
3 | require Test::More; | |
4 | Test::More::plan(skip_all => 'these tests are for testing by the author'); | |
5 | } | |
6 | } | |
7 | ||
8 | BEGIN { | |
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | ||
15 | use Params::Validate qw(validate); | |
16 | use Test::More; | |
17 | ||
18 | { | |
19 | my @p = ( foo => 1 ); | |
20 | ||
21 | eval { validate( @p, { foo => { type => 'SCALAR' } }, ); }; | |
22 | ||
23 | like( | |
24 | $@, | |
25 | qr/\QThe 'foo' parameter ("1") has a type specification which is not a number. It is a string - SCALAR/ | |
26 | ); | |
27 | } | |
28 | ||
29 | { | |
30 | my @p = ( foo => 1 ); | |
31 | ||
32 | eval { validate( @p, { foo => { type => undef } }, ); }; | |
33 | ||
34 | like( | |
35 | $@, | |
36 | qr/\QThe 'foo' parameter ("1") has a type specification which is not a number. It is undef/ | |
37 | ); | |
38 | ||
39 | } | |
40 | ||
41 | done_testing(); |
0 | ||
1 | BEGIN { | |
2 | unless ($ENV{AUTHOR_TESTING}) { | |
3 | require Test::More; | |
4 | Test::More::plan(skip_all => 'these tests are for testing by the author'); | |
5 | } | |
6 | } | |
7 | ||
8 | BEGIN { | |
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | use Test::More; | |
15 | ||
16 | use Devel::Peek qw( SvREFCNT ); | |
17 | use File::Temp qw( tempfile ); | |
18 | use Params::Validate qw( validate SCALAR HANDLE ); | |
19 | ||
20 | { | |
21 | my $fh = tempfile(); | |
22 | my @p = ( | |
23 | foo => 1, | |
24 | bar => $fh, | |
25 | ); | |
26 | ||
27 | my $ref = val1(@p); | |
28 | ||
29 | eval { $ref->{foo} = 2 }; | |
30 | ok( !$@, 'returned hashref values are not read only' ); | |
31 | is( $ref->{foo}, 2, 'double check that setting value worked' ); | |
32 | is( $fh, $ref->{bar}, 'filehandle is not copied during validation' ); | |
33 | } | |
34 | ||
35 | { | |
36 | ||
37 | package ScopeTest; | |
38 | ||
39 | my $live = 0; | |
40 | ||
41 | sub new { $live++; bless {}, shift } | |
42 | sub DESTROY { $live-- } | |
43 | ||
44 | sub Live {$live} | |
45 | } | |
46 | ||
47 | { | |
48 | my @p = ( foo => ScopeTest->new() ); | |
49 | ||
50 | is( | |
51 | ScopeTest->Live(), 1, | |
52 | 'one live object' | |
53 | ); | |
54 | ||
55 | my $ref = val2(@p); | |
56 | ||
57 | isa_ok( $ref->{foo}, 'ScopeTest' ); | |
58 | ||
59 | @p = (); | |
60 | ||
61 | is( | |
62 | ScopeTest->Live(), 1, | |
63 | 'still one live object' | |
64 | ); | |
65 | ||
66 | ok( | |
67 | defined $ref->{foo}, | |
68 | 'foo key stays in scope after original version goes out of scope' | |
69 | ); | |
70 | is( | |
71 | SvREFCNT( $ref->{foo} ), 1, | |
72 | 'ref count for reference is 1' | |
73 | ); | |
74 | ||
75 | undef $ref->{foo}; | |
76 | ||
77 | is( | |
78 | ScopeTest->Live(), 0, | |
79 | 'no live objects' | |
80 | ); | |
81 | } | |
82 | ||
83 | sub val1 { | |
84 | my $ref = validate( | |
85 | @_, { | |
86 | foo => { type => SCALAR }, | |
87 | bar => { type => HANDLE, optional => 1 }, | |
88 | }, | |
89 | ); | |
90 | ||
91 | return $ref; | |
92 | } | |
93 | ||
94 | sub val2 { | |
95 | my $ref = validate( | |
96 | @_, { | |
97 | foo => 1, | |
98 | }, | |
99 | ); | |
100 | ||
101 | return $ref; | |
102 | } | |
103 | ||
104 | done_testing(); |
0 | #!perl -T | |
1 | ||
2 | BEGIN { | |
3 | unless ($ENV{AUTHOR_TESTING}) { | |
4 | require Test::More; | |
5 | Test::More::plan(skip_all => 'these tests are for testing by the author'); | |
6 | } | |
7 | } | |
8 | ||
9 | ||
10 | BEGIN { | |
11 | $ENV{PV_TEST_PERL} = 1; | |
12 | } | |
13 | ||
14 | ||
15 | use strict; | |
16 | use warnings; | |
17 | ||
18 | use Test::Requires { | |
19 | 'Test::Taint' => 0.02, | |
20 | }; | |
21 | ||
22 | use Test::Fatal; | |
23 | use Test::More; | |
24 | ||
25 | use Params::Validate qw( validate validate_pos ARRAYREF ); | |
26 | ||
27 | taint_checking_ok('These tests are meaningless unless we are in taint mode.'); | |
28 | ||
29 | sub test1 { | |
30 | my $def = $0; | |
31 | tainted_ok( $def, 'make sure $def is tainted' ); | |
32 | ||
33 | # The spec is irrelevant, all that matters is that there's a | |
34 | # tainted scalar as the default | |
35 | my %p = validate( @_, { foo => { default => $def } } ); | |
36 | } | |
37 | ||
38 | { | |
39 | is( | |
40 | exception { test1() }, | |
41 | undef, | |
42 | 'no taint error when we validate with tainted default value' | |
43 | ); | |
44 | } | |
45 | ||
46 | sub test2 { | |
47 | return validate_pos( @_, { regex => qr/^b/ } ); | |
48 | } | |
49 | ||
50 | SKIP: | |
51 | { | |
52 | skip 'This test only passes on Perl 5.14+', 1 | |
53 | unless $] >= 5.014; | |
54 | ||
55 | my @p = 'cat'; | |
56 | taint(@p); | |
57 | ||
58 | like( | |
59 | exception { test2(@p) }, | |
60 | qr/\QParameter #1 ("cat") to main::test2 did not pass regex check/, | |
61 | 'no taint error when we validate with tainted value values being validated' | |
62 | ); | |
63 | } | |
64 | ||
65 | done_testing(); |
0 | ||
1 | BEGIN { | |
2 | unless ($ENV{AUTHOR_TESTING}) { | |
3 | require Test::More; | |
4 | Test::More::plan(skip_all => 'these tests are for testing by the author'); | |
5 | } | |
6 | } | |
7 | ||
8 | BEGIN { | |
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | use Test::More; | |
15 | ||
16 | use Params::Validate qw( validate SCALAR ); | |
17 | ||
18 | { | |
19 | my $p = { foo => 1 }; | |
20 | ||
21 | val($p); | |
22 | ||
23 | is_deeply( | |
24 | $p, { foo => 1 }, | |
25 | 'validate does not alter hashref passed to val' | |
26 | ); | |
27 | ||
28 | val2($p); | |
29 | ||
30 | is_deeply( | |
31 | $p, { foo => 1 }, | |
32 | 'validate does not alter hashref passed to val, even with defaults being supplied' | |
33 | ); | |
34 | } | |
35 | ||
36 | sub val { | |
37 | validate( | |
38 | @_, { | |
39 | foo => { optional => 1 }, | |
40 | bar => { optional => 1 }, | |
41 | baz => { optional => 1 }, | |
42 | buz => { optional => 1 }, | |
43 | }, | |
44 | ); | |
45 | ||
46 | return; | |
47 | } | |
48 | ||
49 | sub val2 { | |
50 | validate( | |
51 | @_, { | |
52 | foo => { optional => 1 }, | |
53 | bar => { default => 42 }, | |
54 | baz => { optional => 1 }, | |
55 | buz => { optional => 1 }, | |
56 | }, | |
57 | ); | |
58 | ||
59 | return; | |
60 | } | |
61 | ||
62 | done_testing(); |
0 | #!/usr/bin/perl -w | |
1 | ||
2 | BEGIN { | |
3 | unless ($ENV{AUTHOR_TESTING}) { | |
4 | require Test::More; | |
5 | Test::More::plan(skip_all => 'these tests are for testing by the author'); | |
6 | } | |
7 | } | |
8 | ||
9 | ||
10 | BEGIN { | |
11 | $ENV{PV_TEST_PERL} = 1; | |
12 | } | |
13 | ||
14 | ||
15 | use strict; | |
16 | use warnings; | |
17 | ||
18 | use Test::More; | |
19 | ||
20 | use Params::Validate qw( validate validate_pos SCALAR ); | |
21 | ||
22 | plan skip_all => 'Spec validation is disabled for now'; | |
23 | ||
24 | { | |
25 | my @p = ( foo => 1, bar => 2 ); | |
26 | ||
27 | eval { | |
28 | validate( | |
29 | @p, { | |
30 | foo => { | |
31 | type => SCALAR, | |
32 | callbucks => { | |
33 | 'one' => sub {1} | |
34 | }, | |
35 | }, | |
36 | bar => { type => SCALAR }, | |
37 | } | |
38 | ); | |
39 | }; | |
40 | ||
41 | like( $@, qr/is not an allowed validation spec key/ ); | |
42 | ||
43 | eval { | |
44 | validate( | |
45 | @p, { | |
46 | foo => { | |
47 | hype => SCALAR, | |
48 | callbacks => { | |
49 | 'one' => sub {1} | |
50 | }, | |
51 | }, | |
52 | bar => { type => SCALAR }, | |
53 | } | |
54 | ); | |
55 | }; | |
56 | ||
57 | like( $@, qr/is not an allowed validation spec key/ ); | |
58 | eval { | |
59 | validate( | |
60 | @p, { | |
61 | foo => { | |
62 | type => SCALAR, | |
63 | regexp => qr/^\d+$/, | |
64 | }, | |
65 | bar => { type => SCALAR }, | |
66 | } | |
67 | ); | |
68 | }; | |
69 | ||
70 | like( $@, qr/is not an allowed validation spec key/ ); | |
71 | } | |
72 | ||
73 | done_testing(); |
0 | ||
1 | BEGIN { | |
2 | unless ($ENV{AUTHOR_TESTING}) { | |
3 | require Test::More; | |
4 | Test::More::plan(skip_all => 'these tests are for testing by the author'); | |
5 | } | |
6 | } | |
7 | ||
8 | BEGIN { | |
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | ||
15 | use Params::Validate qw( validate SCALAR SCALARREF ); | |
16 | ||
17 | use Test::More; | |
18 | use Test::Fatal; | |
19 | ||
20 | is( | |
21 | exception { v( foo => qr/foo/ ) }, | |
22 | undef, | |
23 | 'no exception with regex object' | |
24 | ); | |
25 | ||
26 | is( | |
27 | exception { v( foo => 'foo' ) }, | |
28 | undef, | |
29 | 'no exception with plain scalar' | |
30 | ); | |
31 | ||
32 | my $foo = 'foo'; | |
33 | is( | |
34 | exception { v( foo => \$foo ) }, | |
35 | undef, | |
36 | 'no exception with scalar ref' | |
37 | ); | |
38 | ||
39 | done_testing(); | |
40 | ||
41 | sub v { | |
42 | validate( | |
43 | @_, { | |
44 | foo => { type => SCALAR | SCALARREF }, | |
45 | }, | |
46 | ); | |
47 | return; | |
48 | } |
0 | ||
1 | BEGIN { | |
2 | unless ($ENV{AUTHOR_TESTING}) { | |
3 | require Test::More; | |
4 | Test::More::plan(skip_all => 'these tests are for testing by the author'); | |
5 | } | |
6 | } | |
7 | ||
8 | BEGIN { | |
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | ||
15 | use Params::Validate qw( validate SCALAR ); | |
16 | ||
17 | use Test::More; | |
18 | ||
19 | { | |
20 | $@ = 'foo'; | |
21 | v( bar => 42 ); | |
22 | ||
23 | is( | |
24 | $@, | |
25 | 'foo', | |
26 | 'calling validate() does not clobber' | |
27 | ); | |
28 | } | |
29 | ||
30 | done_testing(); | |
31 | ||
32 | sub v { | |
33 | validate( @_, { bar => { type => SCALAR } } ); | |
34 | } |
0 | ||
1 | BEGIN { | |
2 | unless ($ENV{AUTHOR_TESTING}) { | |
3 | require Test::More; | |
4 | Test::More::plan(skip_all => 'these tests are for testing by the author'); | |
5 | } | |
6 | } | |
7 | ||
8 | BEGIN { | |
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | ||
15 | use Test::Fatal; | |
16 | use Test::More; | |
17 | ||
18 | { | |
19 | package Foo; | |
20 | ||
21 | use Params::Validate qw( validate SCALAR ); | |
22 | ||
23 | Params::Validate::validation_options( allow_extra => 1 ); | |
24 | ||
25 | sub test_foo { | |
26 | my %p = validate( @_, { arg1 => { type => SCALAR } } ); | |
27 | print "test foo\n"; | |
28 | } | |
29 | } | |
30 | ||
31 | { | |
32 | package Bar; | |
33 | ||
34 | use Params::Validate qw( validate SCALAR ); | |
35 | Params::Validate::validation_options( allow_extra => 0 ); | |
36 | ||
37 | sub test_bar { | |
38 | ||
39 | # catch die signal | |
40 | local $SIG{__DIE__} = sub { | |
41 | ||
42 | # we died from within Params::Validate (because of wrong_Arg) we | |
43 | # call Foo::test_foo with OK args, but it'll die, because | |
44 | # Params::Validate::PP::options is still set to the options of the | |
45 | # Bar package, and so it won't retreive the one from Foo. | |
46 | Foo::test_foo( arg1 => 1, extra_arg => 2 ); | |
47 | }; | |
48 | ||
49 | # this will die because the arg received is 'wrong_arg' | |
50 | my %p = validate( @_, { arg1 => { type => SCALAR } } ); | |
51 | } | |
52 | } | |
53 | ||
54 | { | |
55 | # This bug only manifests with the pure Perl code because of its use of local | |
56 | # to remember the per-package options. | |
57 | local $TODO = 'Not sure how to fix this one'; | |
58 | unlike( | |
59 | exception { Bar::test_bar( bad_arg => 2 ) }, | |
60 | qr/was passed in the call to Foo::test_foo/, | |
61 | 'no exception from Foo::test_foo when when calling validate() from within a __DIE__ handler' | |
62 | ); | |
63 | } | |
64 | ||
65 | done_testing(); |
0 | ||
1 | BEGIN { | |
2 | unless ($ENV{AUTHOR_TESTING}) { | |
3 | require Test::More; | |
4 | Test::More::plan(skip_all => 'these tests are for testing by the author'); | |
5 | } | |
6 | } | |
7 | ||
8 | BEGIN { | |
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | ||
15 | use Test::More 0.88; | |
16 | ||
17 | use Params::Validate qw( :all ); | |
18 | ||
19 | default_test(); | |
20 | ||
21 | done_testing(); | |
22 | ||
23 | sub default_test { | |
24 | my ( $first, $second ) = validate_pos( | |
25 | @_, | |
26 | { type => SCALAR, optional => 1 }, | |
27 | { type => SCALAR, optional => 1, default => 'must be second one' }, | |
28 | ); | |
29 | ||
30 | is( $first, undef, 'no default for first parameter' ); | |
31 | is( $second, 'must be second one', | |
32 | 'default for second parameter is applied' ); | |
33 | } |
0 | ||
1 | BEGIN { | |
2 | unless ($ENV{AUTHOR_TESTING}) { | |
3 | require Test::More; | |
4 | Test::More::plan(skip_all => 'these tests are for testing by the author'); | |
5 | } | |
6 | } | |
7 | ||
8 | BEGIN { | |
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | ||
15 | use Test::Fatal; | |
16 | use Test::More; | |
17 | ||
18 | { | |
19 | package Foo; | |
20 | ||
21 | use Params::Validate qw( validate ARRAYREF ); | |
22 | ||
23 | sub v1 { | |
24 | my %p = validate( | |
25 | @_, { | |
26 | array => { | |
27 | callbacks => { | |
28 | 'checking array contents' => sub { | |
29 | for my $x ( @{ $_[0] } ) { | |
30 | return 0 unless defined $x && !ref $x; | |
31 | } | |
32 | return 1; | |
33 | }, | |
34 | } | |
35 | } | |
36 | } | |
37 | ); | |
38 | return $p{array}; | |
39 | } | |
40 | } | |
41 | ||
42 | { | |
43 | for my $size ( 100, 1_000, 100_000 ) { | |
44 | my @array = ('x') x $size; | |
45 | is_deeply( | |
46 | Foo::v1( array => \@array ), | |
47 | \@array, | |
48 | "validate() handles $size element array correctly" | |
49 | ); | |
50 | } | |
51 | } | |
52 | ||
53 | done_testing(); |
0 | ||
1 | BEGIN { | |
2 | unless ($ENV{AUTHOR_TESTING}) { | |
3 | require Test::More; | |
4 | Test::More::plan(skip_all => 'these tests are for testing by the author'); | |
5 | } | |
6 | } | |
7 | ||
8 | BEGIN { | |
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | ||
15 | use Test::More; | |
16 | use Params::Validate (); | |
17 | ||
18 | my @types = qw( | |
19 | SCALAR | |
20 | ARRAYREF | |
21 | HASHREF | |
22 | CODEREF | |
23 | GLOB | |
24 | GLOBREF | |
25 | SCALARREF | |
26 | HANDLE | |
27 | BOOLEAN | |
28 | UNDEF | |
29 | OBJECT | |
30 | ); | |
31 | ||
32 | my @subs = qw( | |
33 | validate | |
34 | validate_pos | |
35 | validation_options | |
36 | validate_with | |
37 | ); | |
38 | ||
39 | is_deeply( | |
40 | [ sort @Params::Validate::EXPORT_OK ], | |
41 | [ sort @types, @subs, 'set_options' ], | |
42 | '@EXPORT_OK' | |
43 | ); | |
44 | ||
45 | is_deeply( | |
46 | [ sort keys %Params::Validate::EXPORT_TAGS ], | |
47 | [qw( all types )], | |
48 | 'keys %EXPORT_TAGS' | |
49 | ); | |
50 | ||
51 | is_deeply( | |
52 | [ sort @{ $Params::Validate::EXPORT_TAGS{all} } ], | |
53 | [ sort @types, @subs ], | |
54 | '$EXPORT_TAGS{all}', | |
55 | ); | |
56 | ||
57 | is_deeply( | |
58 | [ sort @{ $Params::Validate::EXPORT_TAGS{types} } ], | |
59 | [ sort @types ], | |
60 | '$EXPORT_TAGS{types}', | |
61 | ); | |
62 | ||
63 | done_testing(); |
0 | ||
1 | BEGIN { | |
2 | unless ($ENV{AUTHOR_TESTING}) { | |
3 | require Test::More; | |
4 | Test::More::plan(skip_all => 'these tests are for testing by the author'); | |
5 | } | |
6 | } | |
7 | ||
8 | BEGIN { | |
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | ||
15 | use Test::More; | |
16 | use Params::Validate qw( validate ); | |
17 | ||
18 | { | |
19 | my $e = _test_args( | |
20 | pos_int => 42, | |
21 | string => 'foo', | |
22 | ); | |
23 | is( | |
24 | $e, | |
25 | q{}, | |
26 | 'no error with good args' | |
27 | ); | |
28 | } | |
29 | ||
30 | { | |
31 | my $e = _test_args( | |
32 | pos_int => 42, | |
33 | string => [], | |
34 | ); | |
35 | like( | |
36 | $e, | |
37 | qr/The 'string' parameter \("ARRAY\(.+\)"\) to main::validate1 did not pass the 'string' callback: ARRAY\(.+\) is not a string/, | |
38 | 'got error for bad string' | |
39 | ); | |
40 | } | |
41 | ||
42 | { | |
43 | my $e = _test_args( | |
44 | pos_int => 0, | |
45 | string => 'foo', | |
46 | ); | |
47 | like( | |
48 | $e, | |
49 | qr/\QThe 'pos_int' parameter ("0") to main::validate1 did not pass the 'pos_int' callback: 0 is not a positive integer/, | |
50 | 'got error for bad pos int (0)' | |
51 | ); | |
52 | } | |
53 | ||
54 | { | |
55 | my $e = _test_args( | |
56 | pos_int => 'bar', | |
57 | string => 'foo', | |
58 | ); | |
59 | like( | |
60 | $e, | |
61 | qr/\QThe 'pos_int' parameter ("bar") to main::validate1 did not pass the 'pos_int' callback: bar is not a positive integer/, | |
62 | 'got error for bad pos int (bar)' | |
63 | ); | |
64 | } | |
65 | ||
66 | { | |
67 | my $e = do { | |
68 | local $@; | |
69 | eval { validate2( string => [] ); }; | |
70 | $@; | |
71 | }; | |
72 | ||
73 | is_deeply( | |
74 | $e, | |
75 | { error => 'not a string' }, | |
76 | 'ref thrown by callback is preserved, not stringified' | |
77 | ); | |
78 | } | |
79 | ||
80 | { | |
81 | my $e = do { | |
82 | local $@; | |
83 | eval { validate3( string => [] ); }; | |
84 | $@; | |
85 | }; | |
86 | ||
87 | like( | |
88 | $e, | |
89 | qr/\QThe 'string' parameter (\E.+?\Q) to main::validate3 did not pass the 'string' callback: Died at \E.+/, | |
90 | 'callback that dies with an empty string generates a sane error message' | |
91 | ); | |
92 | } | |
93 | ||
94 | { | |
95 | my $e = do { | |
96 | local $@; | |
97 | eval { validate4( string => [] ); }; | |
98 | $@; | |
99 | }; | |
100 | ||
101 | like( | |
102 | $e, | |
103 | qr/\QThe 'string' parameter (\E.+?\Q) to main::validate4 did not pass the 'string' callback/, | |
104 | 'callback that does not dies generates a sane error message' | |
105 | ); | |
106 | } | |
107 | ||
108 | sub _test_args { | |
109 | local $@; | |
110 | eval { validate1(@_) }; | |
111 | return $@; | |
112 | } | |
113 | ||
114 | sub validate1 { | |
115 | validate( | |
116 | @_, { | |
117 | pos_int => { | |
118 | callbacks => { | |
119 | pos_int => sub { | |
120 | $_[0] =~ /^[1-9][0-9]*$/ | |
121 | or die "$_[0] is not a positive integer\n"; | |
122 | }, | |
123 | }, | |
124 | }, | |
125 | string => { | |
126 | callbacks => { | |
127 | string => sub { | |
128 | ( defined $_[0] && !ref $_[0] && length $_[0] ) | |
129 | or die "$_[0] is not a string\n"; | |
130 | }, | |
131 | }, | |
132 | }, | |
133 | } | |
134 | ); | |
135 | } | |
136 | ||
137 | sub validate2 { | |
138 | validate( | |
139 | @_, { | |
140 | string => { | |
141 | callbacks => { | |
142 | string => sub { | |
143 | ( defined $_[0] && !ref $_[0] && length $_[0] ) | |
144 | or die { error => 'not a string' }; | |
145 | }, | |
146 | }, | |
147 | }, | |
148 | } | |
149 | ); | |
150 | } | |
151 | ||
152 | sub validate3 { | |
153 | validate( | |
154 | @_, { | |
155 | string => { | |
156 | callbacks => { | |
157 | string => sub { | |
158 | ( defined $_[0] && !ref $_[0] && length $_[0] ) | |
159 | or die; | |
160 | }, | |
161 | }, | |
162 | }, | |
163 | } | |
164 | ); | |
165 | } | |
166 | ||
167 | sub validate4 { | |
168 | validate( | |
169 | @_, { | |
170 | string => { | |
171 | callbacks => { | |
172 | string => sub { | |
173 | return defined $_[0] && !ref $_[0] && length $_[0]; | |
174 | }, | |
175 | }, | |
176 | }, | |
177 | } | |
178 | ); | |
179 | } | |
180 | ||
181 | done_testing(); |
0 | ||
1 | BEGIN { | |
2 | unless ($ENV{AUTHOR_TESTING}) { | |
3 | require Test::More; | |
4 | Test::More::plan(skip_all => 'these tests are for testing by the author'); | |
5 | } | |
6 | } | |
7 | ||
8 | BEGIN { | |
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | ||
15 | use Params::Validate qw( validate SCALAR ); | |
16 | use Test::More; | |
17 | ||
18 | for my $i ( 1 .. 1000 ) { | |
19 | ok( bar(), 'bar()' ); | |
20 | is( foo( foo => $i ), $i, "reentrant validation works ($i)" ); | |
21 | } | |
22 | ||
23 | done_testing(); | |
24 | ||
25 | sub foo { | |
26 | my %p = validate( | |
27 | @_, | |
28 | { | |
29 | foo => { | |
30 | callbacks => { | |
31 | 'call bar' => sub { bar() } | |
32 | }, | |
33 | }, | |
34 | }, | |
35 | ); | |
36 | ||
37 | return $p{foo}; | |
38 | } | |
39 | ||
40 | sub bar { | |
41 | my %p = baz( baz => 42 ); | |
42 | ||
43 | return $p{baz} == 42; | |
44 | } | |
45 | ||
46 | sub baz { | |
47 | my %p = validate( | |
48 | @_, | |
49 | { | |
50 | baz => { | |
51 | type => SCALAR, | |
52 | callbacks => { | |
53 | 'is num' => sub { $_[0] =~ /^\d+$/ }, | |
54 | }, | |
55 | }, | |
56 | }, | |
57 | ); | |
58 | ||
59 | return %p; | |
60 | } |
0 | ||
1 | BEGIN { | |
2 | unless ($ENV{AUTHOR_TESTING}) { | |
3 | require Test::More; | |
4 | Test::More::plan(skip_all => 'these tests are for testing by the author'); | |
5 | } | |
6 | } | |
7 | ||
8 | use strict; | |
9 | use warnings; | |
10 | ||
11 | use Test::More; | |
12 | ||
13 | BEGIN { | |
14 | $ENV{PV_TEST_PERL} = 1; | |
15 | $ENV{PV_WARN_FAILED_IMPLEMENTATION} = 1; | |
16 | } | |
17 | ||
18 | use Module::Implementation 0.04 (); | |
19 | use Params::Validate; | |
20 | ||
21 | is( | |
22 | Module::Implementation::implementation_for('Params::Validate'), | |
23 | 'PP', | |
24 | 'PP implementation is loaded when env var is set' | |
25 | ); | |
26 | ||
27 | done_testing(); |
0 | ||
1 | BEGIN { | |
2 | unless ($ENV{AUTHOR_TESTING}) { | |
3 | require Test::More; | |
4 | Test::More::plan(skip_all => 'these tests are for testing by the author'); | |
5 | } | |
6 | } | |
7 | ||
8 | use strict; | |
9 | use warnings; | |
10 | ||
11 | use Test::More; | |
12 | ||
13 | BEGIN { $ENV{PV_WARN_FAILED_IMPLEMENTATION} = 1 } | |
14 | ||
15 | use Module::Implementation 0.04 (); | |
16 | use Params::Validate; | |
17 | ||
18 | is( | |
19 | Module::Implementation::implementation_for('Params::Validate'), | |
20 | 'XS', | |
21 | 'XS implementation is loaded by default' | |
22 | ); | |
23 | ||
24 | done_testing(); |
0 | ||
1 | BEGIN { | |
2 | unless ($ENV{AUTHOR_TESTING}) { | |
3 | require Test::More; | |
4 | Test::More::plan(skip_all => 'these tests are for testing by the author'); | |
5 | } | |
6 | } | |
7 | ||
8 | use strict; | |
9 | use warnings; | |
10 | ||
11 | use Test::More; | |
12 | ||
13 | BEGIN { | |
14 | $ENV{PARAMS_VALIDATE_IMPLEMENTATION} = 'XS'; | |
15 | $ENV{PV_WARN_FAILED_IMPLEMENTATION} = 1; | |
16 | } | |
17 | ||
18 | use Params::Validate qw( validate SCALAR ); | |
19 | ||
20 | eval { foo( { a => 1 } ) }; | |
21 | ||
22 | ok(1, 'did not segfault'); | |
23 | ||
24 | done_testing(); | |
25 | ||
26 | sub foo { | |
27 | validate( | |
28 | @_, | |
29 | { | |
30 | a => { type => SCALAR, depends => ['%s%s%s'] }, | |
31 | } | |
32 | ); | |
33 | } |
0 | ||
1 | BEGIN { | |
2 | unless ($ENV{AUTHOR_TESTING}) { | |
3 | require Test::More; | |
4 | Test::More::plan(skip_all => 'these tests are for testing by the author'); | |
5 | } | |
6 | } | |
7 | ||
8 | use strict; | |
9 | use warnings; | |
10 | ||
11 | use Test::More; | |
12 | ||
13 | BEGIN { | |
14 | $ENV{PARAMS_VALIDATE_IMPLEMENTATION} = 'XS'; | |
15 | $ENV{PV_WARN_FAILED_IMPLEMENTATION} = 1; | |
16 | } | |
17 | ||
18 | use Params::Validate qw( validate_with ); | |
19 | ||
20 | my $alloc_size; | |
21 | for my $i ( 0 .. 15 ) { | |
22 | $alloc_size = 2**$i; | |
23 | test_array_spec(undef); | |
24 | } | |
25 | ||
26 | ok( 1, 'array validation succeeded with stack realloc' ); | |
27 | ||
28 | for my $i ( 0 .. 15 ) { | |
29 | $alloc_size = 2**$i; | |
30 | test_hash_spec( a => undef ); | |
31 | } | |
32 | ||
33 | ok( 1, 'hash validation succeeded with stack realloc' ); | |
34 | ||
35 | done_testing(); | |
36 | ||
37 | sub grow_stack { | |
38 | my @stuff = (1) x $alloc_size; | |
39 | ||
40 | # "validation" always succeeds - we just need the stack to grow inside a | |
41 | # callback to trigger the bug. | |
42 | return 1; | |
43 | } | |
44 | ||
45 | sub test_array_spec { | |
46 | my @args = validate_with( | |
47 | params => \@_, | |
48 | spec => [ { callbacks => { grow_stack => \&grow_stack } } ], | |
49 | ); | |
50 | } | |
51 | ||
52 | sub test_hash_spec { | |
53 | my %args = validate_with( | |
54 | params => \@_, | |
55 | spec => { | |
56 | a => { callbacks => { grow_stack => \&grow_stack } }, | |
57 | }, | |
58 | ); | |
59 | } |
0 | ||
1 | BEGIN { | |
2 | unless ($ENV{RELEASE_TESTING}) { | |
3 | require Test::More; | |
4 | Test::More::plan(skip_all => 'these tests are for release candidate testing'); | |
5 | } | |
6 | } | |
7 | ||
8 | use strict; | |
9 | use warnings; | |
10 | ||
11 | use Test::LeakTrace qw( no_leaks_ok ); | |
12 | use Test::More; | |
13 | ||
14 | use Params::Validate qw( validate ); | |
15 | ||
16 | subtest( | |
17 | 'callback with default error' => sub { | |
18 | no_leaks_ok( sub { val1( foo => 42 ); }, 'validation passes' ); | |
19 | local $TODO = 'Not sure if all the leaks are in Carp or not'; | |
20 | no_leaks_ok( | |
21 | sub { | |
22 | eval { val1( foo => 'forty two' ) }; | |
23 | }, | |
24 | 'validation fails' | |
25 | ); | |
26 | }, | |
27 | ); | |
28 | ||
29 | subtest( | |
30 | 'callback that dies with string' => sub { | |
31 | no_leaks_ok( sub { val2( foo => 42 ); }, 'validation passes' ); | |
32 | local $TODO = 'Not sure if all the leaks are in Carp or not'; | |
33 | no_leaks_ok( | |
34 | sub { | |
35 | eval { val2( foo => 'forty two' ) }; | |
36 | }, | |
37 | 'validation fails' | |
38 | ); | |
39 | }, | |
40 | ); | |
41 | ||
42 | subtest( | |
43 | 'callback that dies with object' => sub { | |
44 | no_leaks_ok( sub { val3( foo => 42 ); }, 'validation passes' ); | |
45 | no_leaks_ok( | |
46 | sub { | |
47 | eval { val3( foo => 'forty two' ) }; | |
48 | }, | |
49 | 'validation fails' | |
50 | ); | |
51 | }, | |
52 | ); | |
53 | ||
54 | done_testing(); | |
55 | ||
56 | sub val1 { | |
57 | validate( | |
58 | @_, | |
59 | { | |
60 | foo => { | |
61 | callbacks => { | |
62 | 'is int' => sub { $_[0] =~ /^[0-9]+$/ } | |
63 | } | |
64 | }, | |
65 | }, | |
66 | ); | |
67 | } | |
68 | ||
69 | sub val2 { | |
70 | validate( | |
71 | @_, | |
72 | { | |
73 | foo => { | |
74 | callbacks => { | |
75 | 'is int' => sub { | |
76 | $_[0] =~ /^[0-9]+$/ or die "$_[0] is not an integer"; | |
77 | } | |
78 | } | |
79 | }, | |
80 | }, | |
81 | ); | |
82 | } | |
83 | ||
84 | sub val3 { | |
85 | validate( | |
86 | @_, | |
87 | { | |
88 | foo => { | |
89 | callbacks => { | |
90 | 'is int' => sub { | |
91 | $_[0] =~ /^[0-9]+$/ | |
92 | or die { error => "$_[0] is not an integer" }; | |
93 | } | |
94 | } | |
95 | }, | |
96 | }, | |
97 | ); | |
98 | } |
0 | ||
1 | ||
2 | use Test::More; | |
3 | ||
4 | BEGIN { | |
5 | unless ( $ENV{RELEASE_TESTING} ) { | |
6 | plan skip_all => 'these tests are for release testing'; | |
7 | } | |
8 | ||
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | ||
15 | use File::Spec; | |
16 | use lib File::Spec->catdir( 't', 'lib' ); | |
17 | ||
18 | use PVTests::Standard; | |
19 | PVTests::Standard::run_tests(); | |
20 |
0 | ||
1 | ||
2 | use Test::More; | |
3 | ||
4 | BEGIN { | |
5 | unless ( $ENV{RELEASE_TESTING} ) { | |
6 | plan skip_all => 'these tests are for release testing'; | |
7 | } | |
8 | ||
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | ||
15 | use File::Spec; | |
16 | use lib File::Spec->catdir( 't', 'lib' ); | |
17 | ||
18 | BEGIN { $ENV{PERL_NO_VALIDATION} = 1 } | |
19 | ||
20 | use PVTests::Standard; | |
21 | PVTests::Standard::run_tests(); | |
22 | ||
23 |
0 | ||
1 | ||
2 | use Test::More; | |
3 | ||
4 | BEGIN { | |
5 | unless ( $ENV{RELEASE_TESTING} ) { | |
6 | plan skip_all => 'these tests are for release testing'; | |
7 | } | |
8 | ||
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | ||
15 | use File::Spec; | |
16 | use lib File::Spec->catdir( 't', 'lib' ); | |
17 | ||
18 | use PVTests::Defaults; | |
19 | PVTests::Defaults::run_tests(); | |
20 |
0 | ||
1 | ||
2 | use Test::More; | |
3 | ||
4 | BEGIN { | |
5 | unless ( $ENV{RELEASE_TESTING} ) { | |
6 | plan skip_all => 'these tests are for release testing'; | |
7 | } | |
8 | ||
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | ||
15 | use File::Spec; | |
16 | use lib File::Spec->catdir( 't', 'lib' ); | |
17 | ||
18 | BEGIN { $ENV{PERL_NO_VALIDATION} = 1 } | |
19 | ||
20 | use PVTests::Defaults; | |
21 | PVTests::Defaults::run_tests(); | |
22 |
0 | ||
1 | ||
2 | use Test::More; | |
3 | ||
4 | BEGIN { | |
5 | unless ( $ENV{RELEASE_TESTING} ) { | |
6 | plan skip_all => 'these tests are for release testing'; | |
7 | } | |
8 | ||
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | ||
15 | use File::Spec; | |
16 | use lib File::Spec->catdir( 't', 'lib' ); | |
17 | ||
18 | use PVTests; | |
19 | use Test::More; | |
20 | ||
21 | use Params::Validate qw(:all); | |
22 | ||
23 | validation_options( stack_skip => 2 ); | |
24 | ||
25 | sub foo { | |
26 | my %p = validate( @_, { bar => 1 } ); | |
27 | } | |
28 | ||
29 | sub bar { foo(@_) } | |
30 | ||
31 | sub baz { bar(@_) } | |
32 | ||
33 | eval { baz() }; | |
34 | ||
35 | like( $@, qr/mandatory.*missing.*call to main::bar/i ); | |
36 | ||
37 | validation_options( stack_skip => 3 ); | |
38 | ||
39 | eval { baz() }; | |
40 | like( $@, qr/mandatory.*missing.*call to main::baz/i ); | |
41 | ||
42 | validation_options( on_fail => sub { die bless { hash => 'ref' }, 'Dead' } ); | |
43 | ||
44 | eval { baz() }; | |
45 | ||
46 | my $e = $@; | |
47 | is( $e->{hash}, 'ref' ); | |
48 | ok( eval { $e->isa('Dead'); 1; } ); | |
49 | ||
50 | done_testing(); | |
51 |
0 | ||
1 | ||
2 | use Test::More; | |
3 | ||
4 | BEGIN { | |
5 | unless ( $ENV{RELEASE_TESTING} ) { | |
6 | plan skip_all => 'these tests are for release testing'; | |
7 | } | |
8 | ||
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | ||
15 | use File::Spec; | |
16 | use lib File::Spec->catdir( 't', 'lib' ); | |
17 | ||
18 | use PVTests::With; | |
19 | PVTests::With::run_tests(); | |
20 |
0 | ||
1 | ||
2 | use Test::More; | |
3 | ||
4 | BEGIN { | |
5 | unless ( $ENV{RELEASE_TESTING} ) { | |
6 | plan skip_all => 'these tests are for release testing'; | |
7 | } | |
8 | ||
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | ||
15 | use File::Spec; | |
16 | use lib File::Spec->catdir( 't', 'lib' ); | |
17 | ||
18 | BEGIN { $ENV{PERL_NO_VALIDATION} = 1 } | |
19 | ||
20 | use PVTests::With; | |
21 | PVTests::With::run_tests(); | |
22 |
0 | ||
1 | ||
2 | use Test::More; | |
3 | ||
4 | BEGIN { | |
5 | unless ( $ENV{RELEASE_TESTING} ) { | |
6 | plan skip_all => 'these tests are for release testing'; | |
7 | } | |
8 | ||
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | ||
15 | use File::Spec; | |
16 | use lib File::Spec->catdir( 't', 'lib' ); | |
17 | ||
18 | use PVTests::Regex; | |
19 | PVTests::Regex::run_tests(); | |
20 |
0 | ||
1 | ||
2 | use Test::More; | |
3 | ||
4 | BEGIN { | |
5 | unless ( $ENV{RELEASE_TESTING} ) { | |
6 | plan skip_all => 'these tests are for release testing'; | |
7 | } | |
8 | ||
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | ||
15 | use File::Spec; | |
16 | use lib File::Spec->catdir( 't', 'lib' ); | |
17 | ||
18 | BEGIN { $ENV{PERL_NO_VALIDATION} = 1 } | |
19 | ||
20 | use PVTests::Regex; | |
21 | PVTests::Regex::run_tests(); | |
22 |
0 | ||
1 | ||
2 | use Test::More; | |
3 | ||
4 | BEGIN { | |
5 | unless ( $ENV{RELEASE_TESTING} ) { | |
6 | plan skip_all => 'these tests are for release testing'; | |
7 | } | |
8 | ||
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | ||
15 | use File::Spec; | |
16 | use lib File::Spec->catdir( 't', 'lib' ); | |
17 | ||
18 | use PVTests::Callbacks; | |
19 | PVTests::Callbacks::run_tests(); | |
20 |
0 | ||
1 | ||
2 | use Test::More; | |
3 | ||
4 | BEGIN { | |
5 | unless ( $ENV{RELEASE_TESTING} ) { | |
6 | plan skip_all => 'these tests are for release testing'; | |
7 | } | |
8 | ||
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | ||
15 | use File::Spec; | |
16 | use lib File::Spec->catdir( 't', 'lib' ); | |
17 | ||
18 | BEGIN { $ENV{PERL_NO_VALIDATION} = 1 } | |
19 | ||
20 | use PVTests::Callbacks; | |
21 | PVTests::Callbacks::run_tests(); | |
22 |
0 | ||
1 | ||
2 | use Test::More; | |
3 | ||
4 | BEGIN { | |
5 | unless ( $ENV{RELEASE_TESTING} ) { | |
6 | plan skip_all => 'these tests are for release testing'; | |
7 | } | |
8 | ||
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | ||
15 | use File::Spec; | |
16 | use lib File::Spec->catdir( 't', 'lib' ); | |
17 | ||
18 | eval { "$0$^X" && kill 0; 1 }; | |
19 | ||
20 | use PVTests::Standard; | |
21 | PVTests::Standard::run_tests(); | |
22 |
0 | ||
1 | ||
2 | use Test::More; | |
3 | ||
4 | BEGIN { | |
5 | unless ( $ENV{RELEASE_TESTING} ) { | |
6 | plan skip_all => 'these tests are for release testing'; | |
7 | } | |
8 | ||
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | ||
15 | use lib './t'; | |
16 | ||
17 | use Params::Validate qw(validate); | |
18 | ||
19 | use Test::More; | |
20 | plan tests => $] == 5.006 ? 2 : 3; | |
21 | ||
22 | eval { foo() }; | |
23 | like( $@, qr/parameter 'foo'/ ); | |
24 | ||
25 | { | |
26 | local $Params::Validate::NO_VALIDATION = 1; | |
27 | ||
28 | eval { foo() }; | |
29 | is( $@, q{} ); | |
30 | } | |
31 | ||
32 | unless ( $] == 5.006 ) { | |
33 | eval { foo() }; | |
34 | like( $@, qr/parameter 'foo'/ ); | |
35 | } | |
36 | ||
37 | sub foo { | |
38 | validate( @_, { foo => 1 } ); | |
39 | } | |
40 |
0 | ||
1 | ||
2 | use Test::More; | |
3 | ||
4 | BEGIN { | |
5 | unless ( $ENV{RELEASE_TESTING} ) { | |
6 | plan skip_all => 'these tests are for release testing'; | |
7 | } | |
8 | ||
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | ||
15 | use Test::More; | |
16 | ||
17 | use Params::Validate qw(validate validate_with); | |
18 | ||
19 | my @testset; | |
20 | ||
21 | # Generate test cases ... | |
22 | BEGIN { | |
23 | my @lower_case_args = ( foo => 1 ); | |
24 | my @upper_case_args = ( FOO => 1 ); | |
25 | my @mixed_case_args = ( FoO => 1 ); | |
26 | ||
27 | my %lower_case_spec = ( foo => 1 ); | |
28 | my %upper_case_spec = ( FOO => 1 ); | |
29 | my %mixed_case_spec = ( FoO => 1 ); | |
30 | ||
31 | my %arglist = ( | |
32 | lower => \@lower_case_args, | |
33 | upper => \@upper_case_args, | |
34 | mixed => \@mixed_case_args | |
35 | ); | |
36 | ||
37 | my %speclist = ( | |
38 | lower => \%lower_case_spec, | |
39 | upper => \%upper_case_spec, | |
40 | mixed => \%mixed_case_spec | |
41 | ); | |
42 | ||
43 | # XXX - make subs such that user gets to see the error message | |
44 | # when a test fails | |
45 | my $ok_sub = sub { | |
46 | if ($@) { | |
47 | print STDERR $@; | |
48 | } | |
49 | !$@; | |
50 | }; | |
51 | ||
52 | my $nok_sub = sub { | |
53 | my $ok = ( $@ =~ /not listed in the validation options/ ); | |
54 | unless ($ok) { | |
55 | print STDERR $@; | |
56 | } | |
57 | $ok; | |
58 | }; | |
59 | ||
60 | # generate testcases on the fly (I'm too lazy) | |
61 | for my $ignore_case (qw( 0 1 )) { | |
62 | for my $args ( keys %arglist ) { | |
63 | for my $spec ( keys %speclist ) { | |
64 | push @testset, { | |
65 | params => $arglist{$args}, | |
66 | spec => $speclist{$spec}, | |
67 | expect => ( | |
68 | $ignore_case ? $ok_sub | |
69 | : $args eq $spec ? $ok_sub | |
70 | : $nok_sub | |
71 | ), | |
72 | ignore_case => $ignore_case | |
73 | }; | |
74 | } | |
75 | } | |
76 | } | |
77 | } | |
78 | ||
79 | plan tests => ( scalar @testset ) * 2; | |
80 | ||
81 | { | |
82 | ||
83 | # XXX - "called" will be all messed up, but what the heck | |
84 | foreach my $case (@testset) { | |
85 | my %args = eval { | |
86 | validate_with( | |
87 | params => $case->{params}, | |
88 | spec => $case->{spec}, | |
89 | ignore_case => $case->{ignore_case} | |
90 | ); | |
91 | }; | |
92 | ||
93 | ok( $case->{expect}->(%args) ); | |
94 | } | |
95 | ||
96 | # XXX - make sure that it works from validation_options() as well | |
97 | foreach my $case (@testset) { | |
98 | Params::Validate::validation_options( | |
99 | ignore_case => $case->{ignore_case} ); | |
100 | ||
101 | my %args = eval { | |
102 | my @args = @{ $case->{params} }; | |
103 | validate( @args, $case->{spec} ); | |
104 | }; | |
105 | ||
106 | ok( $case->{expect}->(%args) ); | |
107 | } | |
108 | } | |
109 | ||
110 |
0 | ||
1 | ||
2 | use Test::More; | |
3 | ||
4 | BEGIN { | |
5 | unless ( $ENV{RELEASE_TESTING} ) { | |
6 | plan skip_all => 'these tests are for release testing'; | |
7 | } | |
8 | ||
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | ||
15 | use Params::Validate qw(validate validate_with); | |
16 | use Test::More; | |
17 | ||
18 | my $ucfirst_normalizer = sub { return ucfirst lc $_[0] }; | |
19 | ||
20 | sub sub1 { | |
21 | my %args = validate_with( | |
22 | params => \@_, | |
23 | spec => { PaRaMkEy => 1 }, | |
24 | normalize_keys => $ucfirst_normalizer | |
25 | ); | |
26 | ||
27 | return $args{Paramkey}; | |
28 | } | |
29 | ||
30 | sub sub2 { | |
31 | ||
32 | # verify that normalize_callback surpresses ignore_case | |
33 | my %args = validate_with( | |
34 | params => \@_, | |
35 | spec => { PaRaMkEy => 1 }, | |
36 | normalize_keys => $ucfirst_normalizer, | |
37 | ignore_case => 1 | |
38 | ); | |
39 | ||
40 | return $args{Paramkey}; | |
41 | } | |
42 | ||
43 | sub sub3 { | |
44 | ||
45 | # verify that normalize_callback surpresses strip_leading | |
46 | my %args = validate_with( | |
47 | params => \@_, | |
48 | spec => { -PaRaMkEy => 1 }, | |
49 | normalize_keys => $ucfirst_normalizer, | |
50 | strip_leading => '-' | |
51 | ); | |
52 | ||
53 | return $args{-paramkey}; | |
54 | } | |
55 | ||
56 | sub sub4 { | |
57 | my %args = validate_with( | |
58 | params => \@_, | |
59 | spec => { foo => 1 }, | |
60 | normalize_keys => sub {undef} | |
61 | ); | |
62 | } | |
63 | ||
64 | sub sub5 { | |
65 | my %args = validate_with( | |
66 | params => \@_, | |
67 | spec => { foo => 1 }, | |
68 | normalize_keys => sub { return 'a' }, | |
69 | ); | |
70 | } | |
71 | ||
72 | ok( eval { sub1( pArAmKeY => 1 ) } ); | |
73 | ok( eval { sub2( pArAmKeY => 1 ) } ); | |
74 | ok( eval { sub3( -pArAmKeY => 1 ) } ); | |
75 | ||
76 | eval { sub4( foo => 5 ) }; | |
77 | like( $@, qr/normalize_keys.+a defined value/ ); | |
78 | ||
79 | eval { sub5( foo => 5, bar => 5 ) }; | |
80 | like( $@, qr/normalize_keys.+already exists/ ); | |
81 | ||
82 | done_testing(); | |
83 |
0 | ||
1 | ||
2 | use Test::More; | |
3 | ||
4 | BEGIN { | |
5 | unless ( $ENV{RELEASE_TESTING} ) { | |
6 | plan skip_all => 'these tests are for release testing'; | |
7 | } | |
8 | ||
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | ||
15 | use Params::Validate qw(validate validate_pos SCALAR); | |
16 | use Test::More; | |
17 | ||
18 | { | |
19 | my @p = ( foo => 1, bar => 2 ); | |
20 | ||
21 | eval { | |
22 | validate( | |
23 | @p, { | |
24 | foo => { | |
25 | type => SCALAR, | |
26 | callbacks => { | |
27 | 'bigger than bar' => sub { $_[0] > $_[1]->{bar} } | |
28 | }, | |
29 | }, | |
30 | bar => { type => SCALAR }, | |
31 | } | |
32 | ); | |
33 | }; | |
34 | ||
35 | like( $@, qr/bigger than bar/ ); | |
36 | ||
37 | $p[1] = 3; | |
38 | eval { | |
39 | validate( | |
40 | @p, { | |
41 | foo => { | |
42 | type => SCALAR, | |
43 | callbacks => { | |
44 | 'bigger than bar' => sub { $_[0] > $_[1]->{bar} } | |
45 | }, | |
46 | }, | |
47 | bar => { type => SCALAR }, | |
48 | } | |
49 | ); | |
50 | }; | |
51 | ||
52 | is( $@, q{} ); | |
53 | } | |
54 | ||
55 | { | |
56 | my @p = ( 1, 2, 3 ); | |
57 | eval { | |
58 | validate_pos( | |
59 | @p, { | |
60 | type => SCALAR, | |
61 | callbacks => { | |
62 | 'bigger than [1]' => sub { $_[0] > $_[1]->[1] } | |
63 | } | |
64 | }, | |
65 | { type => SCALAR }, | |
66 | { type => SCALAR }, | |
67 | ); | |
68 | }; | |
69 | ||
70 | like( $@, qr/bigger than \[1\]/ ); | |
71 | ||
72 | $p[0] = 5; | |
73 | eval { | |
74 | validate_pos( | |
75 | @p, { | |
76 | type => SCALAR, | |
77 | callbacks => { | |
78 | 'bigger than [1]' => sub { $_[0] > $_[1]->[1] } | |
79 | } | |
80 | }, | |
81 | { type => SCALAR }, | |
82 | { type => SCALAR }, | |
83 | ); | |
84 | }; | |
85 | ||
86 | is( $@, q{} ); | |
87 | } | |
88 | ||
89 | done_testing(); | |
90 |
0 | ||
1 | ||
2 | use Test::More; | |
3 | ||
4 | BEGIN { | |
5 | unless ( $ENV{RELEASE_TESTING} ) { | |
6 | plan skip_all => 'these tests are for release testing'; | |
7 | } | |
8 | ||
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | ||
15 | use Params::Validate qw(validate validate_pos); | |
16 | use Test::More; | |
17 | ||
18 | { | |
19 | my %spec = ( | |
20 | foo => { optional => 1, depends => 'bar' }, | |
21 | bar => { optional => 1 }, | |
22 | ); | |
23 | ||
24 | my @args = ( bar => 1 ); | |
25 | ||
26 | eval { validate( @args, \%spec ) }; | |
27 | ||
28 | is( $@, q{}, "validate() single depends(1): no depends, positive" ); | |
29 | ||
30 | @args = ( foo => 1, bar => 1 ); | |
31 | eval { validate( @args, \%spec ) }; | |
32 | ||
33 | is( $@, q{}, "validate() single depends(2): with depends, positive" ); | |
34 | ||
35 | @args = ( foo => 1 ); | |
36 | eval { validate( @args, \%spec ) }; | |
37 | ||
38 | ok( $@, "validate() single depends(3.a): with depends, negative" ); | |
39 | like( | |
40 | $@, | |
41 | qr(^Parameter 'foo' depends on parameter 'bar', which was not given), | |
42 | "validate() single depends(3.b): check error string" | |
43 | ); | |
44 | } | |
45 | ||
46 | { | |
47 | my %spec = ( | |
48 | foo => { optional => 1, depends => [qw(bar baz)] }, | |
49 | bar => { optional => 1 }, | |
50 | baz => { optional => 1 }, | |
51 | ); | |
52 | ||
53 | # positive, no depends (single, multiple) | |
54 | my @args = ( bar => 1 ); | |
55 | eval { validate( @args, \%spec ) }; | |
56 | is( | |
57 | $@, q{}, | |
58 | "validate() multiple depends(1): no depends, single arg, positive" | |
59 | ); | |
60 | ||
61 | @args = ( bar => 1, baz => 1 ); | |
62 | eval { validate( @args, \%spec ) }; | |
63 | ||
64 | is( | |
65 | $@, q{}, | |
66 | "validate() multiple depends(2): no depends, multiple arg, positive" | |
67 | ); | |
68 | ||
69 | @args = ( foo => 1, bar => 1, baz => 1 ); | |
70 | eval { validate( @args, \%spec ) }; | |
71 | ||
72 | is( $@, q{}, "validate() multiple depends(3): with depends, positive" ); | |
73 | ||
74 | @args = ( foo => 1, bar => 1 ); | |
75 | eval { validate( @args, \%spec ) }; | |
76 | ||
77 | ok( | |
78 | $@, | |
79 | "validate() multiple depends(4.a): with depends, negative, multiple missing" | |
80 | ); | |
81 | like( | |
82 | $@, | |
83 | qr(^Parameter 'foo' depends on parameter 'baz', which was not given), | |
84 | "validate() multiple depends (4.b): check error string" | |
85 | ); | |
86 | ||
87 | @args = ( foo => 1 ); | |
88 | eval { validate( @args, \%spec ) }; | |
89 | ||
90 | ok( | |
91 | $@, | |
92 | "validate() multiple depends(5.a): with depends, negative, multiple missing" | |
93 | ); | |
94 | like( | |
95 | $@, | |
96 | qr(^Parameter 'foo' depends on parameter '(bar|baz)', which was not given), | |
97 | "validate() multiple depends (5.b): check error string" | |
98 | ); | |
99 | } | |
100 | ||
101 | { | |
102 | ||
103 | # bad depends | |
104 | my %spec = ( | |
105 | foo => { optional => 1, depends => { 'bar' => 1 } }, | |
106 | bar => { optional => 1 }, | |
107 | ); | |
108 | ||
109 | my @args = ( foo => 1 ); | |
110 | eval { validate( @args, \%spec ) }; | |
111 | ||
112 | ok( $@, "validate() bad depends spec (1.a): depends is a hashref" ); | |
113 | like( | |
114 | $@, | |
115 | qr(^Arguments to 'depends' must be a scalar or arrayref), | |
116 | "validate() bad depends spec (1.a): check error string" | |
117 | ); | |
118 | } | |
119 | ||
120 | { | |
121 | my @spec = ( { optional => 1 } ); | |
122 | ||
123 | my @args = qw(1); | |
124 | eval { validate_pos( @args, @spec ) }; | |
125 | ||
126 | is( $@, q{}, "validate_pos() no depends, positive" ); | |
127 | } | |
128 | ||
129 | { | |
130 | my @spec = ( { optional => 1, depends => 2 }, { optional => 1 } ); | |
131 | ||
132 | my @args = qw(1 1); | |
133 | eval { validate_pos( @args, @spec ) }; | |
134 | ||
135 | is( | |
136 | $@, q{}, | |
137 | "validate_pos() single depends (1): with depends, positive" | |
138 | ); | |
139 | } | |
140 | ||
141 | { | |
142 | my @spec = ( | |
143 | { optional => 1, depends => 4 }, | |
144 | { optional => 1 }, { optional => 1 }, | |
145 | { optional => 1 } | |
146 | ); | |
147 | ||
148 | my @args = qw(1 0); | |
149 | eval { validate_pos( @args, @spec ) }; | |
150 | ||
151 | ok( $@, "validate_pos() single depends (2.a): with depends, negative" ); | |
152 | like( | |
153 | $@, | |
154 | qr(^Parameter #1 depends on parameter #4, which was not given), | |
155 | "validate_pos() single depends (2.b): check error" | |
156 | ); | |
157 | } | |
158 | ||
159 | { | |
160 | my @spec = ( | |
161 | { optional => 1, depends => [ 2, 3 ] }, | |
162 | { optional => 1 }, | |
163 | 0 | |
164 | ); | |
165 | my @args = qw(1); | |
166 | eval { validate_pos( @args, @spec ) }; | |
167 | ||
168 | ok( | |
169 | $@, | |
170 | "validate_pos() multiple depends (1.a): with depends, bad args negative" | |
171 | ); | |
172 | like( | |
173 | $@, | |
174 | qr{^Arguments to 'depends' for validate_pos\(\) must be a scalar}, | |
175 | "validate_pos() multiple depends (1.b): check error" | |
176 | ); | |
177 | } | |
178 | ||
179 | done_testing(); | |
180 |
0 | #!/usr/bin/perl -T | |
1 | ||
2 | use Test::More; | |
3 | ||
4 | BEGIN { | |
5 | unless ( $ENV{RELEASE_TESTING} ) { | |
6 | plan skip_all => 'these tests are for release testing'; | |
7 | } | |
8 | ||
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | ||
13 | use strict; | |
14 | use warnings; | |
15 | ||
16 | use Test::Requires { | |
17 | 'Test::Taint' => 0.02, | |
18 | }; | |
19 | ||
20 | use Params::Validate qw(validate validate_pos); | |
21 | use Test::More; | |
22 | ||
23 | taint_checking_ok('These tests are meaningless unless we are in taint mode.'); | |
24 | ||
25 | { | |
26 | my $value = 7; | |
27 | taint($value); | |
28 | ||
29 | tainted_ok( $value, 'make sure $value is tainted' ); | |
30 | ||
31 | my @p = ( value => $value ); | |
32 | my %p = validate( | |
33 | @p, { | |
34 | value => { | |
35 | regex => qr/^\d+$/, | |
36 | untaint => 1, | |
37 | }, | |
38 | }, | |
39 | ); | |
40 | ||
41 | untainted_ok( $p{value}, 'value is untainted after validation' ); | |
42 | } | |
43 | ||
44 | { | |
45 | my $value = 'foo'; | |
46 | ||
47 | taint($value); | |
48 | ||
49 | tainted_ok( $value, 'make sure $value is tainted' ); | |
50 | ||
51 | my @p = ($value); | |
52 | my ($new_value) = validate_pos( | |
53 | @p, { | |
54 | regex => qr/foo/, | |
55 | untaint => 1, | |
56 | }, | |
57 | ); | |
58 | ||
59 | untainted_ok( $new_value, 'value is untainted after validation' ); | |
60 | } | |
61 | ||
62 | { | |
63 | my $value = 7; | |
64 | taint($value); | |
65 | ||
66 | tainted_ok( $value, 'make sure $value is tainted' ); | |
67 | ||
68 | my @p = ( value => $value ); | |
69 | my %p = validate( | |
70 | @p, { | |
71 | value => { | |
72 | regex => qr/^\d+$/, | |
73 | }, | |
74 | }, | |
75 | ); | |
76 | ||
77 | tainted_ok( $p{value}, 'value is still tainted after validation' ); | |
78 | } | |
79 | ||
80 | { | |
81 | my $value = 'foo'; | |
82 | ||
83 | taint($value); | |
84 | ||
85 | tainted_ok( $value, 'make sure $value is tainted' ); | |
86 | ||
87 | my @p = ($value); | |
88 | my ($new_value) = validate_pos( | |
89 | @p, { | |
90 | regex => qr/foo/, | |
91 | }, | |
92 | ); | |
93 | ||
94 | tainted_ok( $new_value, 'value is still tainted after validation' ); | |
95 | } | |
96 | ||
97 | done_testing(); | |
98 |
0 | ||
1 | ||
2 | use Test::More; | |
3 | ||
4 | BEGIN { | |
5 | unless ( $ENV{RELEASE_TESTING} ) { | |
6 | plan skip_all => 'these tests are for release testing'; | |
7 | } | |
8 | ||
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | ||
15 | use Params::Validate qw(validate); | |
16 | use Test::More; | |
17 | ||
18 | { | |
19 | my @p = ( foo => 'ClassCan' ); | |
20 | ||
21 | eval { validate( @p, { foo => { can => 'cancan' } }, ); }; | |
22 | ||
23 | is( $@, q{} ); | |
24 | ||
25 | eval { validate( @p, { foo => { can => 'thingy' } }, ); }; | |
26 | ||
27 | like( $@, qr/does not have the method: 'thingy'/ ); | |
28 | } | |
29 | ||
30 | { | |
31 | my @p = ( foo => undef ); | |
32 | eval { validate( @p, { foo => { can => 'baz' } }, ); }; | |
33 | ||
34 | like( $@, qr/does not have the method: 'baz'/ ); | |
35 | } | |
36 | ||
37 | { | |
38 | my $object = bless {}, 'ClassCan'; | |
39 | my @p = ( foo => $object ); | |
40 | ||
41 | eval { validate( @p, { foo => { can => 'cancan' } }, ); }; | |
42 | ||
43 | is( $@, q{} ); | |
44 | ||
45 | eval { validate( @p, { foo => { can => 'thingy' } }, ); }; | |
46 | ||
47 | like( $@, qr/does not have the method: 'thingy'/ ); | |
48 | } | |
49 | ||
50 | { | |
51 | my @p = ( foo => 'SubClass' ); | |
52 | ||
53 | eval { validate( @p, { foo => { can => 'cancan' } }, ); }; | |
54 | ||
55 | is( $@, q{}, 'SubClass->can(cancan)' ); | |
56 | ||
57 | eval { validate( @p, { foo => { can => 'thingy' } }, ); }; | |
58 | ||
59 | like( $@, qr/does not have the method: 'thingy'/ ); | |
60 | } | |
61 | ||
62 | { | |
63 | my $object = bless {}, 'SubClass'; | |
64 | my @p = ( foo => $object ); | |
65 | ||
66 | eval { validate( @p, { foo => { can => 'cancan' } }, ); }; | |
67 | ||
68 | is( $@, q{}, 'SubClass object->can(cancan)' ); | |
69 | ||
70 | eval { validate( @p, { foo => { can => 'thingy' } }, ); }; | |
71 | ||
72 | like( $@, qr/does not have the method: 'thingy'/ ); | |
73 | } | |
74 | ||
75 | { | |
76 | my @p = ( foo => {} ); | |
77 | eval { validate( @p, { foo => { can => 'thingy' } }, ); }; | |
78 | like( $@, qr/does not have the method: 'thingy'/, 'unblessed ref ->can' ); | |
79 | ||
80 | @p = ( foo => 27 ); | |
81 | eval { validate( @p, { foo => { can => 'thingy' } }, ); }; | |
82 | like( $@, qr/does not have the method: 'thingy'/, 'number can' ); | |
83 | ||
84 | @p = ( foo => 'A String' ); | |
85 | eval { validate( @p, { foo => { can => 'thingy' } }, ); }; | |
86 | like( $@, qr/does not have the method: 'thingy'/, 'string can' ); | |
87 | ||
88 | @p = ( foo => undef ); | |
89 | eval { validate( @p, { foo => { can => 'thingy' } }, ); }; | |
90 | like( $@, qr/does not have the method: 'thingy'/, 'undef can' ); | |
91 | } | |
92 | ||
93 | done_testing(); | |
94 | ||
95 | package ClassCan; | |
96 | ||
97 | sub can { | |
98 | return 1 if $_[1] eq 'cancan'; | |
99 | return 0; | |
100 | } | |
101 | ||
102 | sub thingy {1} | |
103 | ||
104 | package SubClass; | |
105 | ||
106 | use base 'ClassCan'; | |
107 |
0 | ||
1 | ||
2 | use Test::More; | |
3 | ||
4 | BEGIN { | |
5 | unless ( $ENV{RELEASE_TESTING} ) { | |
6 | plan skip_all => 'these tests are for release testing'; | |
7 | } | |
8 | ||
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | ||
15 | use Params::Validate qw(validate); | |
16 | use Test::More; | |
17 | ||
18 | { | |
19 | package Overloaded; | |
20 | ||
21 | use overload 'bool' => sub {0}; | |
22 | ||
23 | sub new { bless {} } | |
24 | ||
25 | sub foo {1} | |
26 | } | |
27 | ||
28 | my $ovl = Overloaded->new; | |
29 | ||
30 | { | |
31 | eval { | |
32 | my @p = ( object => $ovl ); | |
33 | validate( @p, { object => { isa => 'Overloaded' } } ); | |
34 | }; | |
35 | ||
36 | is( $@, q{}, 'overloaded object->isa' ); | |
37 | } | |
38 | ||
39 | { | |
40 | eval { | |
41 | my @p = ( object => $ovl ); | |
42 | validate( @p, { object => { can => 'foo' } } ); | |
43 | }; | |
44 | ||
45 | is( $@, q{}, 'overloaded object->foo' ); | |
46 | } | |
47 | ||
48 | done_testing(); | |
49 |
0 | ||
1 | ||
2 | use Test::More; | |
3 | ||
4 | BEGIN { | |
5 | unless ( $ENV{RELEASE_TESTING} ) { | |
6 | plan skip_all => 'these tests are for release testing'; | |
7 | } | |
8 | ||
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | ||
15 | use Test::Requires { | |
16 | Readonly => '1.03', | |
17 | 'Scalar::Util' => '1.20', | |
18 | }; | |
19 | ||
20 | use Params::Validate qw(validate validate_pos SCALAR); | |
21 | use Test::More; | |
22 | ||
23 | plan skip_all => 'These tests fail with Readonly 1.50 for some reason' | |
24 | if Readonly::->VERSION() =~ /^v?1.5/; | |
25 | ||
26 | { | |
27 | Readonly my $spec => { foo => 1 }; | |
28 | my @p = ( foo => 'hello' ); | |
29 | ||
30 | eval { validate( @p, $spec ) }; | |
31 | is( $@, q{}, 'validate() call succeeded with Readonly spec hashref' ); | |
32 | } | |
33 | ||
34 | { | |
35 | Readonly my $spec => { type => SCALAR }; | |
36 | my @p = 'hello'; | |
37 | ||
38 | eval { validate_pos( @p, $spec ) }; | |
39 | is( $@, q{}, 'validate_pos() call succeeded with Readonly spec hashref' ); | |
40 | } | |
41 | ||
42 | { | |
43 | Readonly my %spec => ( foo => { type => SCALAR } ); | |
44 | my @p = ( foo => 'hello' ); | |
45 | ||
46 | eval { validate( @p, \%spec ) }; | |
47 | is( $@, q{}, 'validate() call succeeded with Readonly spec hash' ); | |
48 | } | |
49 | ||
50 | done_testing(); | |
51 |
0 | ||
1 | ||
2 | use Test::More; | |
3 | ||
4 | BEGIN { | |
5 | unless ( $ENV{RELEASE_TESTING} ) { | |
6 | plan skip_all => 'these tests are for release testing'; | |
7 | } | |
8 | ||
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | ||
15 | use Params::Validate qw(validate validate_pos SCALAR); | |
16 | use Test::More; | |
17 | ||
18 | { | |
19 | package Tie::SimpleArray; | |
20 | use Tie::Array; | |
21 | use base 'Tie::StdArray'; | |
22 | } | |
23 | ||
24 | { | |
25 | ||
26 | package Tie::SimpleHash; | |
27 | use Tie::Hash; | |
28 | use base 'Tie::StdHash'; | |
29 | } | |
30 | ||
31 | { | |
32 | tie my @p, 'Tie::SimpleArray'; | |
33 | ||
34 | my %spec = ( foo => 1 ); | |
35 | push @p, ( foo => 'hello' ); | |
36 | ||
37 | eval { validate( @p, \%spec ) }; | |
38 | warn $@ if $@; | |
39 | is( | |
40 | $@, q{}, | |
41 | 'validate() call succeeded with tied params array and regular hashref spec' | |
42 | ); | |
43 | } | |
44 | ||
45 | SKIP: | |
46 | { | |
47 | skip 'Params::Validate segfaults with tied hash for spec', 1; | |
48 | ||
49 | my @p; | |
50 | tie my %spec, 'Tie::SimpleHash'; | |
51 | ||
52 | $spec{foo} = 1; | |
53 | push @p, ( foo => 'hello' ); | |
54 | ||
55 | eval { validate( @p, \%spec ) }; | |
56 | warn $@ if $@; | |
57 | is( | |
58 | $@, q{}, | |
59 | 'validate() call succeeded with regular params array and tied hashref spec' | |
60 | ); | |
61 | } | |
62 | ||
63 | SKIP: | |
64 | { | |
65 | skip 'Params::Validate segfaults with tied hash for spec', 1; | |
66 | ||
67 | tie my @p, 'Tie::SimpleArray'; | |
68 | tie my %spec, 'Tie::SimpleHash'; | |
69 | ||
70 | $spec{foo} = 1; | |
71 | push @p, ( foo => 'hello' ); | |
72 | ||
73 | eval { validate( @p, \%spec ) }; | |
74 | warn $@ if $@; | |
75 | is( | |
76 | $@, q{}, | |
77 | 'validate() call succeeded with tied params array and tied hashref spec' | |
78 | ); | |
79 | } | |
80 | ||
81 | { | |
82 | tie my @p, 'Tie::SimpleArray'; | |
83 | my %spec; | |
84 | ||
85 | $spec{type} = SCALAR; | |
86 | push @p, 'hello'; | |
87 | ||
88 | eval { validate_pos( @p, \%spec ) }; | |
89 | warn $@ if $@; | |
90 | is( | |
91 | $@, q{}, | |
92 | 'validate_pos() call succeeded with tied params array and regular hashref spec' | |
93 | ); | |
94 | } | |
95 | ||
96 | SKIP: | |
97 | { | |
98 | skip 'Params::Validate segfaults with tied hash for spec', 1; | |
99 | ||
100 | my @p; | |
101 | tie my %spec, 'Tie::SimpleHash'; | |
102 | ||
103 | $spec{type} = SCALAR; | |
104 | push @p, 'hello'; | |
105 | ||
106 | eval { validate_pos( @p, \%spec ) }; | |
107 | warn $@ if $@; | |
108 | is( | |
109 | $@, q{}, | |
110 | 'validate_pos() call succeeded with regular params array and tied hashref spec' | |
111 | ); | |
112 | } | |
113 | ||
114 | SKIP: | |
115 | { | |
116 | skip 'Params::Validate segfaults with tied hash for spec', 1; | |
117 | ||
118 | tie my @p, 'Tie::SimpleArray'; | |
119 | tie my %spec, 'Tie::SimpleHash'; | |
120 | ||
121 | $spec{type} = SCALAR; | |
122 | push @p, 'hello'; | |
123 | ||
124 | eval { validate_pos( @p, \%spec ) }; | |
125 | warn $@ if $@; | |
126 | is( | |
127 | $@, q{}, | |
128 | 'validate_pos() call succeeded with tied params array and tied hashref spec' | |
129 | ); | |
130 | } | |
131 | ||
132 | done_testing(); | |
133 |
0 | ||
1 | ||
2 | use Test::More; | |
3 | ||
4 | BEGIN { | |
5 | unless ( $ENV{RELEASE_TESTING} ) { | |
6 | plan skip_all => 'these tests are for release testing'; | |
7 | } | |
8 | ||
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | ||
15 | use Params::Validate qw(validate); | |
16 | use Test::More; | |
17 | ||
18 | { | |
19 | my @w; | |
20 | local $SIG{__WARN__} = sub { push @w, @_ }; | |
21 | ||
22 | my @p = ( foo => undef ); | |
23 | eval { validate( @p, { foo => { regex => qr/^bar/ } } ) }; | |
24 | ok( $@, 'validation failed' ); | |
25 | ok( !@w, 'no warnings' ); | |
26 | } | |
27 | ||
28 | done_testing(); | |
29 |
0 | ||
1 | ||
2 | use Test::More; | |
3 | ||
4 | BEGIN { | |
5 | unless ( $ENV{RELEASE_TESTING} ) { | |
6 | plan skip_all => 'these tests are for release testing'; | |
7 | } | |
8 | ||
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | ||
15 | use Params::Validate qw(validate); | |
16 | use Test::More; | |
17 | ||
18 | { | |
19 | my @p = ( foo => 'ClassISA' ); | |
20 | ||
21 | eval { validate( @p, { foo => { isa => 'FooBar' } }, ); }; | |
22 | ||
23 | is( $@, q{}, 'no error checking if ClassISA->isa(FooBar)' ); | |
24 | ||
25 | eval { validate( @p, { foo => { isa => 'Thingy' } }, ); }; | |
26 | ||
27 | like( $@, qr/was not a 'Thingy'/ ); | |
28 | } | |
29 | ||
30 | { | |
31 | my @p = ( foo => undef ); | |
32 | eval { validate( @p, { foo => { isa => 'FooBar' } }, ); }; | |
33 | ||
34 | like( $@, qr/was not a 'FooBar'/ ); | |
35 | } | |
36 | ||
37 | { | |
38 | my @p = ( foo => 'SubClass' ); | |
39 | ||
40 | eval { validate( @p, { foo => { isa => 'ClassISA' } }, ); }; | |
41 | ||
42 | is( $@, q{}, 'SubClass->isa(ClassISA)' ); | |
43 | ||
44 | eval { validate( @p, { foo => { isa => 'FooBar' } }, ); }; | |
45 | ||
46 | is( $@, q{}, 'SubClass->isa(FooBar)' ); | |
47 | ||
48 | eval { validate( @p, { foo => { isa => 'Thingy' } }, ); }; | |
49 | ||
50 | like( $@, qr/was not a 'Thingy'/ ); | |
51 | } | |
52 | ||
53 | { | |
54 | my @p = ( foo => bless {}, 'SubClass' ); | |
55 | ||
56 | eval { validate( @p, { foo => { isa => 'ClassISA' } }, ); }; | |
57 | ||
58 | is( $@, q{}, 'SubClass->isa(ClassISA)' ); | |
59 | ||
60 | eval { validate( @p, { foo => { isa => 'FooBar' } }, ); }; | |
61 | ||
62 | is( $@, q{}, 'SubClass->isa(FooBar)' ); | |
63 | ||
64 | eval { validate( @p, { foo => { isa => 'Thingy' } }, ); }; | |
65 | ||
66 | like( $@, qr/was not a 'Thingy'/ ); | |
67 | } | |
68 | ||
69 | { | |
70 | my @p = ( foo => {} ); | |
71 | eval { validate( @p, { foo => { isa => 'Thingy' } }, ); }; | |
72 | like( $@, qr/was not a 'Thingy'/, 'unblessed ref ->isa' ); | |
73 | ||
74 | @p = ( foo => 27 ); | |
75 | eval { validate( @p, { foo => { isa => 'Thingy' } }, ); }; | |
76 | like( $@, qr/was not a 'Thingy'/, 'number isa' ); | |
77 | ||
78 | @p = ( foo => 'A String' ); | |
79 | eval { validate( @p, { foo => { isa => 'Thingy' } }, ); }; | |
80 | like( $@, qr/was not a 'Thingy'/, 'string isa' ); | |
81 | ||
82 | @p = ( foo => undef ); | |
83 | eval { validate( @p, { foo => { isa => 'Thingy' } }, ); }; | |
84 | like( $@, qr/was not a 'Thingy'/, 'undef isa' ); | |
85 | } | |
86 | ||
87 | done_testing(); | |
88 | ||
89 | package ClassISA; | |
90 | ||
91 | sub isa { | |
92 | return 1 if $_[1] eq 'FooBar'; | |
93 | return $_[0]->SUPER::isa( $_[1] ); | |
94 | } | |
95 | ||
96 | sub thingy {1} | |
97 | ||
98 | package SubClass; | |
99 | ||
100 | use base 'ClassISA'; | |
101 |
0 | ||
1 | ||
2 | use Test::More; | |
3 | ||
4 | BEGIN { | |
5 | unless ( $ENV{RELEASE_TESTING} ) { | |
6 | plan skip_all => 'these tests are for release testing'; | |
7 | } | |
8 | ||
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | ||
15 | use Params::Validate qw(validate); | |
16 | use Test::More; | |
17 | ||
18 | { | |
19 | my @p = ( foo => 1 ); | |
20 | ||
21 | eval { validate( @p, { foo => { type => 'SCALAR' } }, ); }; | |
22 | ||
23 | like( | |
24 | $@, | |
25 | qr/\QThe 'foo' parameter ("1") has a type specification which is not a number. It is a string - SCALAR/ | |
26 | ); | |
27 | } | |
28 | ||
29 | { | |
30 | my @p = ( foo => 1 ); | |
31 | ||
32 | eval { validate( @p, { foo => { type => undef } }, ); }; | |
33 | ||
34 | like( | |
35 | $@, | |
36 | qr/\QThe 'foo' parameter ("1") has a type specification which is not a number. It is undef/ | |
37 | ); | |
38 | ||
39 | } | |
40 | ||
41 | done_testing(); | |
42 |
0 | ||
1 | ||
2 | use Test::More; | |
3 | ||
4 | BEGIN { | |
5 | unless ( $ENV{RELEASE_TESTING} ) { | |
6 | plan skip_all => 'these tests are for release testing'; | |
7 | } | |
8 | ||
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | use Test::More; | |
15 | ||
16 | use Devel::Peek qw( SvREFCNT ); | |
17 | use File::Temp qw( tempfile ); | |
18 | use Params::Validate qw( validate SCALAR HANDLE ); | |
19 | ||
20 | { | |
21 | my $fh = tempfile(); | |
22 | my @p = ( | |
23 | foo => 1, | |
24 | bar => $fh, | |
25 | ); | |
26 | ||
27 | my $ref = val1(@p); | |
28 | ||
29 | eval { $ref->{foo} = 2 }; | |
30 | ok( !$@, 'returned hashref values are not read only' ); | |
31 | is( $ref->{foo}, 2, 'double check that setting value worked' ); | |
32 | is( $fh, $ref->{bar}, 'filehandle is not copied during validation' ); | |
33 | } | |
34 | ||
35 | { | |
36 | ||
37 | package ScopeTest; | |
38 | ||
39 | my $live = 0; | |
40 | ||
41 | sub new { $live++; bless {}, shift } | |
42 | sub DESTROY { $live-- } | |
43 | ||
44 | sub Live {$live} | |
45 | } | |
46 | ||
47 | { | |
48 | my @p = ( foo => ScopeTest->new() ); | |
49 | ||
50 | is( | |
51 | ScopeTest->Live(), 1, | |
52 | 'one live object' | |
53 | ); | |
54 | ||
55 | my $ref = val2(@p); | |
56 | ||
57 | isa_ok( $ref->{foo}, 'ScopeTest' ); | |
58 | ||
59 | @p = (); | |
60 | ||
61 | is( | |
62 | ScopeTest->Live(), 1, | |
63 | 'still one live object' | |
64 | ); | |
65 | ||
66 | ok( | |
67 | defined $ref->{foo}, | |
68 | 'foo key stays in scope after original version goes out of scope' | |
69 | ); | |
70 | is( | |
71 | SvREFCNT( $ref->{foo} ), 1, | |
72 | 'ref count for reference is 1' | |
73 | ); | |
74 | ||
75 | undef $ref->{foo}; | |
76 | ||
77 | is( | |
78 | ScopeTest->Live(), 0, | |
79 | 'no live objects' | |
80 | ); | |
81 | } | |
82 | ||
83 | sub val1 { | |
84 | my $ref = validate( | |
85 | @_, { | |
86 | foo => { type => SCALAR }, | |
87 | bar => { type => HANDLE, optional => 1 }, | |
88 | }, | |
89 | ); | |
90 | ||
91 | return $ref; | |
92 | } | |
93 | ||
94 | sub val2 { | |
95 | my $ref = validate( | |
96 | @_, { | |
97 | foo => 1, | |
98 | }, | |
99 | ); | |
100 | ||
101 | return $ref; | |
102 | } | |
103 | ||
104 | done_testing(); | |
105 |
0 | #!perl -T | |
1 | ||
2 | use Test::More; | |
3 | ||
4 | BEGIN { | |
5 | unless ( $ENV{RELEASE_TESTING} ) { | |
6 | plan skip_all => 'these tests are for release testing'; | |
7 | } | |
8 | ||
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | ||
13 | use strict; | |
14 | use warnings; | |
15 | ||
16 | use Test::Requires { | |
17 | 'Test::Taint' => 0.02, | |
18 | }; | |
19 | ||
20 | use Test::Fatal; | |
21 | use Test::More; | |
22 | ||
23 | use Params::Validate qw( validate validate_pos ARRAYREF ); | |
24 | ||
25 | taint_checking_ok('These tests are meaningless unless we are in taint mode.'); | |
26 | ||
27 | sub test1 { | |
28 | my $def = $0; | |
29 | tainted_ok( $def, 'make sure $def is tainted' ); | |
30 | ||
31 | # The spec is irrelevant, all that matters is that there's a | |
32 | # tainted scalar as the default | |
33 | my %p = validate( @_, { foo => { default => $def } } ); | |
34 | } | |
35 | ||
36 | { | |
37 | is( | |
38 | exception { test1() }, | |
39 | undef, | |
40 | 'no taint error when we validate with tainted default value' | |
41 | ); | |
42 | } | |
43 | ||
44 | sub test2 { | |
45 | return validate_pos( @_, { regex => qr/^b/ } ); | |
46 | } | |
47 | ||
48 | SKIP: | |
49 | { | |
50 | skip 'This test only passes on Perl 5.14+', 1 | |
51 | unless $] >= 5.014; | |
52 | ||
53 | my @p = 'cat'; | |
54 | taint(@p); | |
55 | ||
56 | like( | |
57 | exception { test2(@p) }, | |
58 | qr/\QParameter #1 ("cat") to main::test2 did not pass regex check/, | |
59 | 'no taint error when we validate with tainted value values being validated' | |
60 | ); | |
61 | } | |
62 | ||
63 | done_testing(); | |
64 |
0 | ||
1 | ||
2 | use Test::More; | |
3 | ||
4 | BEGIN { | |
5 | unless ( $ENV{RELEASE_TESTING} ) { | |
6 | plan skip_all => 'these tests are for release testing'; | |
7 | } | |
8 | ||
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | use Test::More; | |
15 | ||
16 | use Params::Validate qw( validate SCALAR ); | |
17 | ||
18 | { | |
19 | my $p = { foo => 1 }; | |
20 | ||
21 | val($p); | |
22 | ||
23 | is_deeply( | |
24 | $p, { foo => 1 }, | |
25 | 'validate does not alter hashref passed to val' | |
26 | ); | |
27 | ||
28 | val2($p); | |
29 | ||
30 | is_deeply( | |
31 | $p, { foo => 1 }, | |
32 | 'validate does not alter hashref passed to val, even with defaults being supplied' | |
33 | ); | |
34 | } | |
35 | ||
36 | sub val { | |
37 | validate( | |
38 | @_, { | |
39 | foo => { optional => 1 }, | |
40 | bar => { optional => 1 }, | |
41 | baz => { optional => 1 }, | |
42 | buz => { optional => 1 }, | |
43 | }, | |
44 | ); | |
45 | ||
46 | return; | |
47 | } | |
48 | ||
49 | sub val2 { | |
50 | validate( | |
51 | @_, { | |
52 | foo => { optional => 1 }, | |
53 | bar => { default => 42 }, | |
54 | baz => { optional => 1 }, | |
55 | buz => { optional => 1 }, | |
56 | }, | |
57 | ); | |
58 | ||
59 | return; | |
60 | } | |
61 | ||
62 | done_testing(); | |
63 |
0 | #!/usr/bin/perl -w | |
1 | ||
2 | use Test::More; | |
3 | ||
4 | BEGIN { | |
5 | unless ( $ENV{RELEASE_TESTING} ) { | |
6 | plan skip_all => 'these tests are for release testing'; | |
7 | } | |
8 | ||
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | ||
13 | use strict; | |
14 | use warnings; | |
15 | ||
16 | use Test::More; | |
17 | ||
18 | use Params::Validate qw( validate validate_pos SCALAR ); | |
19 | ||
20 | plan skip_all => 'Spec validation is disabled for now'; | |
21 | ||
22 | { | |
23 | my @p = ( foo => 1, bar => 2 ); | |
24 | ||
25 | eval { | |
26 | validate( | |
27 | @p, { | |
28 | foo => { | |
29 | type => SCALAR, | |
30 | callbucks => { | |
31 | 'one' => sub {1} | |
32 | }, | |
33 | }, | |
34 | bar => { type => SCALAR }, | |
35 | } | |
36 | ); | |
37 | }; | |
38 | ||
39 | like( $@, qr/is not an allowed validation spec key/ ); | |
40 | ||
41 | eval { | |
42 | validate( | |
43 | @p, { | |
44 | foo => { | |
45 | hype => SCALAR, | |
46 | callbacks => { | |
47 | 'one' => sub {1} | |
48 | }, | |
49 | }, | |
50 | bar => { type => SCALAR }, | |
51 | } | |
52 | ); | |
53 | }; | |
54 | ||
55 | like( $@, qr/is not an allowed validation spec key/ ); | |
56 | eval { | |
57 | validate( | |
58 | @p, { | |
59 | foo => { | |
60 | type => SCALAR, | |
61 | regexp => qr/^\d+$/, | |
62 | }, | |
63 | bar => { type => SCALAR }, | |
64 | } | |
65 | ); | |
66 | }; | |
67 | ||
68 | like( $@, qr/is not an allowed validation spec key/ ); | |
69 | } | |
70 | ||
71 | done_testing(); | |
72 |
0 | ||
1 | ||
2 | use Test::More; | |
3 | ||
4 | BEGIN { | |
5 | unless ( $ENV{RELEASE_TESTING} ) { | |
6 | plan skip_all => 'these tests are for release testing'; | |
7 | } | |
8 | ||
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | ||
15 | use Params::Validate qw( validate SCALAR SCALARREF ); | |
16 | ||
17 | use Test::More; | |
18 | use Test::Fatal; | |
19 | ||
20 | is( | |
21 | exception { v( foo => qr/foo/ ) }, | |
22 | undef, | |
23 | 'no exception with regex object' | |
24 | ); | |
25 | ||
26 | is( | |
27 | exception { v( foo => 'foo' ) }, | |
28 | undef, | |
29 | 'no exception with plain scalar' | |
30 | ); | |
31 | ||
32 | my $foo = 'foo'; | |
33 | is( | |
34 | exception { v( foo => \$foo ) }, | |
35 | undef, | |
36 | 'no exception with scalar ref' | |
37 | ); | |
38 | ||
39 | done_testing(); | |
40 | ||
41 | sub v { | |
42 | validate( | |
43 | @_, { | |
44 | foo => { type => SCALAR | SCALARREF }, | |
45 | }, | |
46 | ); | |
47 | return; | |
48 | } | |
49 |
0 | ||
1 | ||
2 | use Test::More; | |
3 | ||
4 | BEGIN { | |
5 | unless ( $ENV{RELEASE_TESTING} ) { | |
6 | plan skip_all => 'these tests are for release testing'; | |
7 | } | |
8 | ||
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | ||
15 | use Params::Validate qw( validate SCALAR ); | |
16 | ||
17 | use Test::More; | |
18 | ||
19 | { | |
20 | $@ = 'foo'; | |
21 | v( bar => 42 ); | |
22 | ||
23 | is( | |
24 | $@, | |
25 | 'foo', | |
26 | 'calling validate() does not clobber' | |
27 | ); | |
28 | } | |
29 | ||
30 | done_testing(); | |
31 | ||
32 | sub v { | |
33 | validate( @_, { bar => { type => SCALAR } } ); | |
34 | } | |
35 |
0 | ||
1 | ||
2 | use Test::More; | |
3 | ||
4 | BEGIN { | |
5 | unless ( $ENV{RELEASE_TESTING} ) { | |
6 | plan skip_all => 'these tests are for release testing'; | |
7 | } | |
8 | ||
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | ||
15 | use Test::Fatal; | |
16 | use Test::More; | |
17 | ||
18 | { | |
19 | package Foo; | |
20 | ||
21 | use Params::Validate qw( validate SCALAR ); | |
22 | ||
23 | Params::Validate::validation_options( allow_extra => 1 ); | |
24 | ||
25 | sub test_foo { | |
26 | my %p = validate( @_, { arg1 => { type => SCALAR } } ); | |
27 | print "test foo\n"; | |
28 | } | |
29 | } | |
30 | ||
31 | { | |
32 | package Bar; | |
33 | ||
34 | use Params::Validate qw( validate SCALAR ); | |
35 | Params::Validate::validation_options( allow_extra => 0 ); | |
36 | ||
37 | sub test_bar { | |
38 | ||
39 | # catch die signal | |
40 | local $SIG{__DIE__} = sub { | |
41 | ||
42 | # we died from within Params::Validate (because of wrong_Arg) we | |
43 | # call Foo::test_foo with OK args, but it'll die, because | |
44 | # Params::Validate::PP::options is still set to the options of the | |
45 | # Bar package, and so it won't retreive the one from Foo. | |
46 | Foo::test_foo( arg1 => 1, extra_arg => 2 ); | |
47 | }; | |
48 | ||
49 | # this will die because the arg received is 'wrong_arg' | |
50 | my %p = validate( @_, { arg1 => { type => SCALAR } } ); | |
51 | } | |
52 | } | |
53 | ||
54 | { | |
55 | # This bug only manifests with the pure Perl code because of its use of local | |
56 | # to remember the per-package options. | |
57 | local $TODO = 'Not sure how to fix this one'; | |
58 | unlike( | |
59 | exception { Bar::test_bar( bad_arg => 2 ) }, | |
60 | qr/was passed in the call to Foo::test_foo/, | |
61 | 'no exception from Foo::test_foo when when calling validate() from within a __DIE__ handler' | |
62 | ); | |
63 | } | |
64 | ||
65 | done_testing(); | |
66 |
0 | ||
1 | ||
2 | use Test::More; | |
3 | ||
4 | BEGIN { | |
5 | unless ( $ENV{RELEASE_TESTING} ) { | |
6 | plan skip_all => 'these tests are for release testing'; | |
7 | } | |
8 | ||
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | ||
15 | use Test::More 0.88; | |
16 | ||
17 | use Params::Validate qw( :all ); | |
18 | ||
19 | default_test(); | |
20 | ||
21 | done_testing(); | |
22 | ||
23 | sub default_test { | |
24 | my ( $first, $second ) = validate_pos( | |
25 | @_, | |
26 | { type => SCALAR, optional => 1 }, | |
27 | { type => SCALAR, optional => 1, default => 'must be second one' }, | |
28 | ); | |
29 | ||
30 | is( $first, undef, '01 no default for first' ); | |
31 | is( $second, 'must be second one', '01 default for second' ); | |
32 | } | |
33 |
0 | ||
1 | ||
2 | use Test::More; | |
3 | ||
4 | BEGIN { | |
5 | unless ( $ENV{RELEASE_TESTING} ) { | |
6 | plan skip_all => 'these tests are for release testing'; | |
7 | } | |
8 | ||
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | ||
15 | use Test::Fatal; | |
16 | use Test::More; | |
17 | ||
18 | { | |
19 | package Foo; | |
20 | ||
21 | use Params::Validate qw( validate ARRAYREF ); | |
22 | ||
23 | sub v1 { | |
24 | my %p = validate( | |
25 | @_, { | |
26 | array => { | |
27 | callbacks => { | |
28 | 'checking array contents' => sub { | |
29 | for my $x ( @{ $_[0] } ) { | |
30 | return 0 unless defined $x && !ref $x; | |
31 | } | |
32 | return 1; | |
33 | }, | |
34 | } | |
35 | } | |
36 | } | |
37 | ); | |
38 | return $p{array}; | |
39 | } | |
40 | } | |
41 | ||
42 | { | |
43 | for my $size ( 100, 1_000, 100_000 ) { | |
44 | my @array = ('x') x $size; | |
45 | is_deeply( | |
46 | Foo::v1( array => \@array ), | |
47 | \@array, | |
48 | "validate() handles $size element array correctly" | |
49 | ); | |
50 | } | |
51 | } | |
52 | ||
53 | done_testing(); | |
54 |
0 | ||
1 | ||
2 | use Test::More; | |
3 | ||
4 | BEGIN { | |
5 | unless ( $ENV{RELEASE_TESTING} ) { | |
6 | plan skip_all => 'these tests are for release testing'; | |
7 | } | |
8 | ||
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | ||
15 | use Test::More; | |
16 | use Params::Validate (); | |
17 | ||
18 | my @types = qw( | |
19 | SCALAR | |
20 | ARRAYREF | |
21 | HASHREF | |
22 | CODEREF | |
23 | GLOB | |
24 | GLOBREF | |
25 | SCALARREF | |
26 | HANDLE | |
27 | BOOLEAN | |
28 | UNDEF | |
29 | OBJECT | |
30 | ); | |
31 | ||
32 | my @subs = qw( | |
33 | validate | |
34 | validate_pos | |
35 | validation_options | |
36 | validate_with | |
37 | ); | |
38 | ||
39 | is_deeply( | |
40 | [ sort @Params::Validate::EXPORT_OK ], | |
41 | [ sort @types, @subs, 'set_options' ], | |
42 | '@EXPORT_OK' | |
43 | ); | |
44 | ||
45 | is_deeply( | |
46 | [ sort keys %Params::Validate::EXPORT_TAGS ], | |
47 | [qw( all types )], | |
48 | 'keys %EXPORT_TAGS' | |
49 | ); | |
50 | ||
51 | is_deeply( | |
52 | [ sort @{ $Params::Validate::EXPORT_TAGS{all} } ], | |
53 | [ sort @types, @subs ], | |
54 | '$EXPORT_TAGS{all}', | |
55 | ); | |
56 | ||
57 | is_deeply( | |
58 | [ sort @{ $Params::Validate::EXPORT_TAGS{types} } ], | |
59 | [ sort @types ], | |
60 | '$EXPORT_TAGS{types}', | |
61 | ); | |
62 | ||
63 | done_testing(); | |
64 |
0 | ||
1 | ||
2 | use Test::More; | |
3 | ||
4 | BEGIN { | |
5 | unless ( $ENV{RELEASE_TESTING} ) { | |
6 | plan skip_all => 'these tests are for release testing'; | |
7 | } | |
8 | ||
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | ||
15 | use Test::More; | |
16 | use Params::Validate qw( validate ); | |
17 | ||
18 | { | |
19 | my $e = _test_args( | |
20 | pos_int => 42, | |
21 | string => 'foo', | |
22 | ); | |
23 | is( | |
24 | $e, | |
25 | q{}, | |
26 | 'no error with good args' | |
27 | ); | |
28 | } | |
29 | ||
30 | { | |
31 | my $e = _test_args( | |
32 | pos_int => 42, | |
33 | string => [], | |
34 | ); | |
35 | like( | |
36 | $e, | |
37 | qr/The 'string' parameter \("ARRAY\(.+\)"\) to main::validate1 did not pass the 'string' callback: ARRAY\(.+\) is not a string/, | |
38 | 'got error for bad string' | |
39 | ); | |
40 | } | |
41 | ||
42 | { | |
43 | my $e = _test_args( | |
44 | pos_int => 0, | |
45 | string => 'foo', | |
46 | ); | |
47 | like( | |
48 | $e, | |
49 | qr/\QThe 'pos_int' parameter ("0") to main::validate1 did not pass the 'pos_int' callback: 0 is not a positive integer/, | |
50 | 'got error for bad pos int (0)' | |
51 | ); | |
52 | } | |
53 | ||
54 | { | |
55 | my $e = _test_args( | |
56 | pos_int => 'bar', | |
57 | string => 'foo', | |
58 | ); | |
59 | like( | |
60 | $e, | |
61 | qr/\QThe 'pos_int' parameter ("bar") to main::validate1 did not pass the 'pos_int' callback: bar is not a positive integer/, | |
62 | 'got error for bad pos int (bar)' | |
63 | ); | |
64 | } | |
65 | ||
66 | { | |
67 | my $e = do { | |
68 | local $@; | |
69 | eval { validate2( string => [] ); }; | |
70 | $@; | |
71 | }; | |
72 | ||
73 | is_deeply( | |
74 | $e, | |
75 | { error => 'not a string' }, | |
76 | 'ref thrown by callback is preserved, not stringified' | |
77 | ); | |
78 | } | |
79 | ||
80 | { | |
81 | my $e = do { | |
82 | local $@; | |
83 | eval { validate3( string => [] ); }; | |
84 | $@; | |
85 | }; | |
86 | ||
87 | like( | |
88 | $e, | |
89 | qr/\QThe 'string' parameter (\E.+?\Q) to main::validate3 did not pass the 'string' callback: Died at \E.+/, | |
90 | 'callback that dies with an empty string generates a sane error message' | |
91 | ); | |
92 | } | |
93 | ||
94 | { | |
95 | my $e = do { | |
96 | local $@; | |
97 | eval { validate4( string => [] ); }; | |
98 | $@; | |
99 | }; | |
100 | ||
101 | like( | |
102 | $e, | |
103 | qr/\QThe 'string' parameter (\E.+?\Q) to main::validate4 did not pass the 'string' callback\E\s+at/, | |
104 | 'callback that does not dies generates a sane error message' | |
105 | ); | |
106 | } | |
107 | ||
108 | sub _test_args { | |
109 | local $@; | |
110 | eval { validate1(@_) }; | |
111 | return $@; | |
112 | } | |
113 | ||
114 | sub validate1 { | |
115 | validate( | |
116 | @_, { | |
117 | pos_int => { | |
118 | callbacks => { | |
119 | pos_int => sub { | |
120 | $_[0] =~ /^[1-9][0-9]*$/ | |
121 | or die "$_[0] is not a positive integer\n"; | |
122 | }, | |
123 | }, | |
124 | }, | |
125 | string => { | |
126 | callbacks => { | |
127 | string => sub { | |
128 | ( defined $_[0] && !ref $_[0] && length $_[0] ) | |
129 | or die "$_[0] is not a string\n"; | |
130 | }, | |
131 | }, | |
132 | }, | |
133 | } | |
134 | ); | |
135 | } | |
136 | ||
137 | sub validate2 { | |
138 | validate( | |
139 | @_, { | |
140 | string => { | |
141 | callbacks => { | |
142 | string => sub { | |
143 | ( defined $_[0] && !ref $_[0] && length $_[0] ) | |
144 | or die { error => 'not a string' }; | |
145 | }, | |
146 | }, | |
147 | }, | |
148 | } | |
149 | ); | |
150 | } | |
151 | ||
152 | sub validate3 { | |
153 | validate( | |
154 | @_, { | |
155 | string => { | |
156 | callbacks => { | |
157 | string => sub { | |
158 | ( defined $_[0] && !ref $_[0] && length $_[0] ) | |
159 | or die; | |
160 | }, | |
161 | }, | |
162 | }, | |
163 | } | |
164 | ); | |
165 | } | |
166 | ||
167 | sub validate4 { | |
168 | validate( | |
169 | @_, { | |
170 | string => { | |
171 | callbacks => { | |
172 | string => sub { | |
173 | return defined $_[0] && !ref $_[0] && length $_[0]; | |
174 | }, | |
175 | }, | |
176 | }, | |
177 | } | |
178 | ); | |
179 | } | |
180 | ||
181 | done_testing(); | |
182 |
0 | ||
1 | ||
2 | use Test::More; | |
3 | ||
4 | BEGIN { | |
5 | unless ( $ENV{RELEASE_TESTING} ) { | |
6 | plan skip_all => 'these tests are for release testing'; | |
7 | } | |
8 | ||
9 | $ENV{PV_TEST_PERL} = 1; | |
10 | } | |
11 | ||
12 | use strict; | |
13 | use warnings; | |
14 | ||
15 | use Params::Validate qw( validate SCALAR ); | |
16 | use Test::More; | |
17 | ||
18 | for my $i ( 1 .. 1000 ) { | |
19 | ok( bar(), 'bar()' ); | |
20 | is( foo( foo => $i ), $i, "reentrant validation works ($i)" ); | |
21 | } | |
22 | ||
23 | done_testing(); | |
24 | ||
25 | sub foo { | |
26 | my %p = validate( | |
27 | @_, | |
28 | { | |
29 | foo => { | |
30 | callbacks => { | |
31 | 'call bar' => sub { bar() } | |
32 | }, | |
33 | }, | |
34 | }, | |
35 | ); | |
36 | ||
37 | return $p{foo}; | |
38 | } | |
39 | ||
40 | sub bar { | |
41 | my %p = baz( baz => 42 ); | |
42 | ||
43 | return $p{baz} == 42; | |
44 | } | |
45 | ||
46 | sub baz { | |
47 | my %p = validate( | |
48 | @_, | |
49 | { | |
50 | baz => { | |
51 | type => SCALAR, | |
52 | callbacks => { | |
53 | 'is num' => sub { $_[0] =~ /^\d+$/ }, | |
54 | }, | |
55 | }, | |
56 | }, | |
57 | ); | |
58 | ||
59 | return %p; | |
60 | } | |
61 |
0 | ||
1 | BEGIN { | |
2 | unless ($ENV{RELEASE_TESTING}) { | |
3 | require Test::More; | |
4 | Test::More::plan(skip_all => 'these tests are for release candidate testing'); | |
5 | } | |
6 | } | |
7 | ||
8 | use strict; | |
9 | use warnings; | |
10 | ||
11 | use Test::More; | |
12 | ||
13 | BEGIN { | |
14 | $ENV{PV_TEST_PERL} = 1; | |
15 | $ENV{PV_WARN_FAILED_IMPLEMENTATION} = 1; | |
16 | } | |
17 | ||
18 | use Module::Implementation 0.04 (); | |
19 | use Params::Validate; | |
20 | ||
21 | is( | |
22 | Module::Implementation::implementation_for('Params::Validate'), | |
23 | 'PP', | |
24 | 'PP implementation is loaded when env var is set' | |
25 | ); | |
26 | ||
27 | done_testing(); |
0 | ||
1 | BEGIN { | |
2 | unless ($ENV{RELEASE_TESTING}) { | |
3 | require Test::More; | |
4 | Test::More::plan(skip_all => 'these tests are for release candidate testing'); | |
5 | } | |
6 | } | |
7 | ||
8 | use strict; | |
9 | use warnings; | |
10 | ||
11 | use Test::More; | |
12 | ||
13 | BEGIN { $ENV{PV_WARN_FAILED_IMPLEMENTATION} = 1 } | |
14 | ||
15 | use Module::Implementation 0.04 (); | |
16 | use Params::Validate; | |
17 | ||
18 | is( | |
19 | Module::Implementation::implementation_for('Params::Validate'), | |
20 | 'XS', | |
21 | 'XS implementation is loaded by default' | |
22 | ); | |
23 | ||
24 | done_testing(); |
0 | ||
1 | BEGIN { | |
2 | unless ($ENV{RELEASE_TESTING}) { | |
3 | require Test::More; | |
4 | Test::More::plan(skip_all => 'these tests are for release candidate testing'); | |
5 | } | |
6 | } | |
7 | ||
8 | use strict; | |
9 | use warnings; | |
10 | ||
11 | use Test::More; | |
12 | ||
13 | BEGIN { | |
14 | $ENV{PARAMS_VALIDATE_IMPLEMENTATION} = 'XS'; | |
15 | $ENV{PV_WARN_FAILED_IMPLEMENTATION} = 1; | |
16 | } | |
17 | ||
18 | use Params::Validate qw( validate SCALAR ); | |
19 | ||
20 | eval { foo( { a => 1 } ) }; | |
21 | ||
22 | ok(1, 'did not segfault'); | |
23 | ||
24 | done_testing(); | |
25 | ||
26 | sub foo { | |
27 | validate( | |
28 | @_, | |
29 | { | |
30 | a => { type => SCALAR, depends => ['%s%s%s'] }, | |
31 | } | |
32 | ); | |
33 | } |
0 | ||
1 | BEGIN { | |
2 | unless ($ENV{RELEASE_TESTING}) { | |
3 | require Test::More; | |
4 | Test::More::plan(skip_all => 'these tests are for release candidate testing'); | |
5 | } | |
6 | } | |
7 | ||
8 | use strict; | |
9 | use warnings; | |
10 | ||
11 | use Test::More; | |
12 | ||
13 | BEGIN { | |
14 | $ENV{PARAMS_VALIDATE_IMPLEMENTATION} = 'XS'; | |
15 | $ENV{PV_WARN_FAILED_IMPLEMENTATION} = 1; | |
16 | } | |
17 | ||
18 | use Params::Validate qw( validate_with ); | |
19 | ||
20 | my $alloc_size; | |
21 | for my $i ( 0 .. 15 ) { | |
22 | $alloc_size = 2**$i; | |
23 | test_array_spec(undef); | |
24 | } | |
25 | ||
26 | ok( 1, 'array validation succeeded with stack realloc' ); | |
27 | ||
28 | for my $i ( 0 .. 15 ) { | |
29 | $alloc_size = 2**$i; | |
30 | test_hash_spec( a => undef ); | |
31 | } | |
32 | ||
33 | ok( 1, 'hash validation succeeded with stack realloc' ); | |
34 | ||
35 | done_testing(); | |
36 | ||
37 | sub grow_stack { | |
38 | my @stuff = (1) x $alloc_size; | |
39 | ||
40 | # "validation" always succeeds - we just need the stack to grow inside a | |
41 | # callback to trigger the bug. | |
42 | return 1; | |
43 | } | |
44 | ||
45 | sub test_array_spec { | |
46 | my @args = validate_with( | |
47 | params => \@_, | |
48 | spec => [ { callbacks => { grow_stack => \&grow_stack } } ], | |
49 | ); | |
50 | } | |
51 | ||
52 | sub test_hash_spec { | |
53 | my %args = validate_with( | |
54 | params => \@_, | |
55 | spec => { | |
56 | a => { callbacks => { grow_stack => \&grow_stack } }, | |
57 | }, | |
58 | ); | |
59 | } |