File Coverage

blib/lib/Test2/Util/UUID.pm
Criterion Covered Total %
statement 105 110 95.4
branch 20 38 52.6
condition 13 21 61.9
subroutine 26 26 100.0
pod 1 3 33.3
total 165 198 83.3


line stmt bran cond sub pod time code
1             package Test2::Util::UUID;
2 1     1   559526 use strict;
  1         2  
  1         45  
3 1     1   8 use warnings;
  1         2  
  1         98  
4              
5             our $VERSION = '0.002010';
6              
7 1     1   7 use Carp qw/croak/;
  1         2  
  1         4399  
8              
9             my %EXPORT = (
10             looks_like_uuid => 1,
11             gen_uuid => 1,
12             GEN_UUID_BACKEND => 1,
13             uuid2bin => 1,
14             bin2uuid => 1,
15             );
16              
17             sub import {
18 5     5   49 my $class = shift;
19 5         18 my $caller = caller;
20              
21 5         16 my %gen_params;
22             my %import;
23              
24 5         27 while (my $arg = shift @_) {
25 29 100       79 if ($EXPORT{$arg}) {
26 21         67 $import{$arg}++;
27 21         56 next;
28             }
29              
30 8 50 66     44 if ($arg eq 'warn' || $arg eq 'backends') {
31 8         24 $gen_params{$arg} = shift @_;
32 8         25 next;
33             }
34              
35 0         0 croak "Invalid argument '$arg'";
36             }
37              
38 5         24 my $subs = $class->get_gen_uuid(%gen_params);
39              
40 5         23 for my $name (keys %import) {
41 21 50 66     256 my $sub = $subs->{$name} || $class->can($name) or croak "'$name' is not available for import";
42              
43 1     1   13 no strict 'refs';
  1         3  
  1         1835  
44 21         40 *{"$caller\::$name"} = $sub;
  21         219  
45             }
46              
47 5         11494 return;
48             }
49              
50             my %GEN_UUID_CACHE;
51              
52 12     12 0 13765 sub clear_cache { %GEN_UUID_CACHE = () }
53              
54             sub get_gen_uuid {
55 17     17 0 895 my $class = shift;
56 17         76 my %params = @_;
57              
58 17 50 66     91 my $warn = $params{warn} // ($ENV{TEST2_UUID_NO_WARN} ? 0 : 1);
59 17 50 66     65 my $backends = $params{backends} // ($ENV{TEST2_UUID_BACKEND} ? [split /\s*,\s*/, $ENV{TEST2_UUID_BACKEND}] : ['UUID', 'Data::UUID::MT', 'UUID::Tiny', 'Data::UUID']);
60              
61 17         455 for my $backend (@$backends) {
62 17 100       77 return $GEN_UUID_CACHE{$backend} if $GEN_UUID_CACHE{$backend};
63              
64 13         54 my $meth = lc("_gen_$backend");
65 13         80 $meth =~ s/::/_/g;
66              
67 13 50       124 croak "'$backend' is not supported" unless $class->can($meth);
68              
69 13 50       55 $GEN_UUID_CACHE{$backend} = $class->$meth($warn) or next;
70 13     12   82 $GEN_UUID_CACHE{$backend}->{GEN_UUID_BACKEND} = sub() { $backend };
  12         756  
71 13         77 return $GEN_UUID_CACHE{$backend};
72             }
73              
74 0         0 croak "No UUID generator found, please install one of these: UUID, Data::UUID::MT, Data::UUID, or UUID::Tiny. ('UUID' is preferred over the others)\n";
75             }
76              
77             sub _gen_uuid {
78 4     4   9 my $class = shift;
79 4         11 my ($warn) = @_;
80              
81 4         7 local $@;
82 4 50       10 return undef unless eval { require UUID; 1 };
  4         692  
  4         3514  
83              
84 4 50       16 unless (eval { UUID->VERSION('0.35'); 1 }) {
  4         68  
  4         28  
85 0 0       0 warn "UUID version is too old, need 0.35 or greater to avoid a fork related bug. Please upgrade the UUID module.\n"
86             if $warn;
87              
88 0         0 return;
89             }
90              
91             return {
92 59     59   32303 gen_uuid => sub { uc(UUID::uuid7->()) },
93 1     1   142 bin2uuid => sub { my $out; UUID::unparse($_[0], $out); uc($out) },
  1         7  
  1         6  
94 1     1   3 uuid2bin => sub { my $out; UUID::parse($_[0], $out); $out },
  1         33  
  1         4  
95 4         75 };
96             }
97              
98             sub _gen_data_uuid_mt {
99 3     3   10 my $class = shift;
100 3         9 my ($warn) = @_;
101              
102 3         26 local $@;
103 3 50       10 return undef unless eval { require Data::UUID::MT; 1 };
  3         35  
  3         15  
104              
105 3         26 my $ug = Data::UUID::MT->new(version => 4);
106             my $out = {
107 59     59   73510 gen_uuid => sub { uc($ug->create_string()) },
108 3         22906 };
109              
110 3 50       11 if (eval { require UUID::Tiny; 1 }) {
  3         782  
  3         58500  
111 1     1   7 $out->{uuid2bin} = sub { UUID::Tiny::string_to_uuid($_[0]) },
112 1     1   198 $out->{bin2uuid} = sub { uc(UUID::Tiny::uuid_to_string($_[0])) },
113 3         46 }
114              
115 3         23 return $out;
116             }
117              
118             sub _gen_uuid_tiny {
119 3     3   445 my $class = shift;
120 3         13 my ($warn) = @_;
121              
122 3         8 local $@;
123              
124 3 50       10 return undef unless eval { require UUID::Tiny; 1 };
  3         35  
  3         15  
125              
126 3 50       11 warn "Using UUID::Tiny for uuid generation. UUID::Tiny is significantly slower than the 'UUID' or 'Data::UUID::MT' modules, please install 'UUID' or 'Data::UUID::MT' if possible. If you insist on using UUID::Tiny you can set the TEST2_UUID_NO_WARN environment variable.\n"
127             if $warn;
128              
129             return {
130 58     58   39279 gen_uuid => sub { uc(UUID::Tiny::create_uuid_as_string(UUID::Tiny::UUID_V4())) },
131 1     1   145 bin2uuid => sub { uc(UUID::Tiny::uuid_to_string($_[0])) },
132 1     1   6 uuid2bin => sub { UUID::Tiny::string_to_uuid($_[0]) },
133 3         45 };
134             }
135              
136             sub _gen_data_uuid {
137 3     3   8 my $class = shift;
138 3         8 my ($warn) = @_;
139              
140 3         6 local $@;
141 3 50       7 return undef unless eval { require Data::UUID; 1 };
  3         27  
  3         12  
142              
143 3 50       11 warn "Using Data::UUID to generate UUIDs, this works, but the UUIDs will not be suitible as database keys. Please install the 'UUID', 'Data::UUID::MT' or the slower but pure perl 'UUID::Tiny' cpan modules for better UUIDs. If you insist on using Data::UUID you can set the TEST2_UUID_NO_WARN environment variable.\n"
144             if $warn;
145              
146 3         6 my ($UG, $UG_PID);
147              
148             my $UG_INIT = sub {
149 64 50 66 64   1741 return $UG if $UG && $UG_PID && $UG_PID == $$;
      66        
150              
151 3         19 $UG_PID = $$;
152 3         777 return $UG = Data::UUID->new;
153 3         15 };
154              
155             # Initialize it here in this PID to start
156 3         10 $UG_INIT->();
157              
158             return {
159 59     59   241289 gen_uuid => sub { uc($UG_INIT->()->create_str()) },
160 1     1   149 bin2uuid => sub { uc($UG_INIT->()->to_string($_[0])) },
161 1     1   5 uuid2bin => sub { $UG_INIT->()->from_string($_[0]) },
162 3         82 };
163             }
164              
165             sub looks_like_uuid {
166 40     40 1 22252 my ($in) = @_;
167 40 50 33     523 return $in if $in && $in =~ m/^[A-F0-9]{8}-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{12}$/i;
168 0           return undef;
169             }
170              
171             1;
172              
173             __END__