File Coverage

blib/lib/Test/MockDBI.pm
Criterion Covered Total %
statement 253 307 82.4
branch 98 142 69.0
condition 28 48 58.3
subroutine 29 35 82.8
pod 6 12 50.0
total 414 544 76.1


line stmt bran cond sub pod time code
1             package Test::MockDBI;
2              
3 50     50   699190 use 5.008; # minimum Perl is V5.8.0
  50         128  
4 50     50   201 use strict;
  50         53  
  50         838  
5 50     50   174 use warnings;
  50         49  
  50         1153  
6 50     50   158 use Carp;
  50         54  
  50         2559  
7 50     50   17365 use Clone;
  50         92923  
  50         1911  
8 50     50   20671 use Test::MockObject::Extends;
  50         269038  
  50         179  
9 50     50   1304 use Scalar::Util;
  50         56  
  50         9969  
10              
11             our $VERSION = '0.66_03';
12              
13             my $instance = undef;
14              
15             =head1 NAME
16            
17             Test::MockDBI - Mocked DBI interface for testing purposes
18              
19             =head1 SYNOPSIS
20              
21             use Test::MockDBI;
22            
23             my $mi = Test::MockDBI::get_instance();
24            
25             Sets a fake return value for the rows statementhandler
26             $mi->set_retval( method => rows, retval => sub{ return scalar( @somearray ); });
27            
28             $mi->set_retval( method => 'bind_param', retval => undef);
29             Same as:
30             $mi->bad_method('bind_param');
31            
32             You can also specify return values for specific sqls
33             $mi->set_retval( method => rows, retval => sub{ return scalar( @somearray ); }, sql => 'select id from names');
34            
35             $mi->set_retval( method => 'bind_param', retval => undef, sql => 'select id from names where id < ?');
36             Same as:
37             $mi->bad_method('bind_param', 'select id from names where id < ?');
38            
39            
40            
41             =cut
42              
43              
44             sub import{
45            
46 50     50   19855 require Test::MockDBI::Db;
47 50         15506 require Test::MockDBI::St;
48            
49            
50 50         286 $instance = bless {
51             methods => {
52             },
53             _regexes => {}
54             }, __PACKAGE__;
55            
56 50         187 Test::MockDBI::Db->import($instance);
57 50         131 Test::MockDBI::St->import($instance);
58            
59 50         330 my $mock = Test::MockObject::Extends->new();
60            
61 50         871 $mock->fake_module("DBI",
62             connect => \&_dbi_connect,
63             _concat_hash_sorted => \&_dbi__concat_hash_sorted,
64             _get_sorted_hash_keys => \&_dbi__get_sorted_hash_keys,
65             looks_like_number => \&_dbi__looks_like_number
66             );
67            
68 50         3553 my %dbi_methods = (
69             "DBI::db" => ['clone', 'data_sources', 'do', 'last_inserted_id', 'selectrow_array', 'selectrow_hashref', 'selectall_arrayref',
70             'selectall_hashref', 'selectcol_arrayref', 'prepare', 'prepare_cached', 'commit', 'rollback', 'begin_work', 'disconnect',
71             'ping', 'get_info', 'table_info', 'column_info', 'primary_key_info', 'primary_key', 'foreign_key_info', 'statistics_info',
72             'tables', 'type_info_all', 'type_info', 'quote', 'quote_identifier', 'take_imp_data', 'err', 'errstr'],
73             "DBI::st" => ['bind_param', 'bind_param_inout', 'bind_param_array', 'execute', 'execute_array', 'execute_array_fetch',
74             'fetchrow_arrayref', 'fetchrow_array', 'fetchrow_hashref', 'fetchall_arrayref', 'fetchall_hashref', 'finish',
75             'rows', 'bind_col', 'bind_columns', 'dump_results', 'err', 'errstr', 'fetch']
76             );
77            
78 50         170 my %packages = ( "Test::MockDBI::Db" => "DBI::db", "Test::MockDBI::St" => "DBI::st" );
79            
80 50         194 foreach my $mock_package ( keys %packages ){
81 100         7231 my %available_methods = ();
82            
83             #Takes the package as a parameter
84             my $map_subs = sub{
85 50     50   229 no strict 'refs';
  50         63  
  50         96925  
86 200     200   236 my $p = shift;
87 200         201 return map{ s/^_dbi_//; $_ => $p . '::_dbi_' . $_ } grep { m/^_dbi_/ } grep { defined &{"$p\::$_"} } keys %{"$p\::"};
  1100         1635  
  1100         2666  
  3500         3571  
  4650         2539  
  4650         11530  
  200         1123  
88 100         399 };
89              
90 100         208 %available_methods = $map_subs->($mock_package);
91             #Also find methods inherited by the package
92 100         4378 my @isalist = eval( '@' . $mock_package . '::ISA');
93 100 50       383 die('Could not eval @' . $mock_package .'::ISA') if $@;
94 100         155 foreach my $isa_package ( @isalist ){
95             #Pray for no duplicates
96 100         168 my %isamethods = $map_subs->($isa_package);
97 100         457 @available_methods{keys %isamethods} = values %isamethods;
98             }
99              
100 100         144 my %args = ();
101 100         89 foreach my $method ( @{ $dbi_methods{ $packages{$mock_package} } } ){
  100         205  
102 2500 100       5079 if(grep { m/^$method$/} keys %available_methods){
  26900         55443  
103 1100         33752 $args{$method} = eval( '\&' . $available_methods{$method});
104 1100 50       3506 die("Error during fake module setup. " . $@) if($@);
105             }else{
106             #Need to check if the method is inherited from a parent package
107 1400     0   55941 $args{$method} = eval('sub{ die \'Test::MockDBI-ERROR : Unsupported method ' . $method . '\'; } ');
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  1         28  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
108             }
109             }
110 100         678 $mock->fake_module( $packages{ $mock_package }, %args );
111             }
112 50         7444 $mock->fake_new( "DBI" );
113 50         40457 return 1;
114             }
115             ##################################
116             #
117             # OO - Test MockDBI API
118             #
119             ###################################
120              
121             =head1 PUBLIC INTERFACE
122              
123             Methods available on the Test::MockDBI instance.
124              
125             =over 4
126              
127             =item reset()
128              
129             Method for reseting all mock returnvalues \ bad_params etc
130            
131             =cut
132              
133             sub reset{
134 8     8 1 1524 my ($self) = @_;
135 8         40 $self->{methods} = {};
136             }
137              
138             =item bad_method()
139              
140             This method is basically a alias for calling set_retval with the return value undef.
141            
142             Args:
143             $method_name - The name of the method which should return undef
144             $matching_sql (Optional) - The sql matching condition
145            
146             Returns:
147             On success: 1
148             On failure: undef
149            
150             The method also supports calling the method with the following arguments:
151             $method_name, $dbi_testing_type, $matching_sql
152             This will issue a warning as it is deprecated.
153              
154             =cut
155              
156             sub bad_method{
157 29     29 1 9160 my $self = shift;
158 29         42 my %args = ();
159            
160 29 100 66     162 if(scalar(@_) == 3 && $_[0] =~ m/^[a-z_]+$/ && $_[1] =~ m/^\d+$/){
      66        
161 14         59 warn "You have called bad_method in an deprecated way. Please consult the documentation\n";
162 14         480 $args{method} = shift;
163            
164             #Throw away $dbi_testing_type
165 14         12 shift;
166 14         15 my $matchingsql = shift;
167 14 50 33     32 if($matchingsql && $matchingsql ne ''){
168 0         0 my $regex = qr/$matchingsql/;
169 0         0 $args{sql} = $regex;
170             }
171             }else{
172 15         28 %args = @_;
173             }
174            
175 29         27 $args{retval} = undef;
176              
177 29         68 return $self->set_retval( %args );
178             }
179              
180             =item bad_param()
181            
182             Args:
183             $p_value - The value that will cause bind_param to return undef
184             $sql (Optional) - The sql matching condition
185            
186             Returns:
187             On success: 1
188             On failure: undef
189            
190             The method also supports calling the method with the following arguments:
191             $dbi_testing_type, $p_num, $p_value
192             This will issue a warning as it is deprecated.
193              
194             =cut
195              
196             sub bad_param{
197 6     6 1 2411 my $self = shift;
198 6         9 my %args;
199            
200             #We assume its a legacy call if its length is 3 and arg 1 && 2 is numeric
201 6 100 66     100 if(scalar(@_) == 3 && $_[0] =~ m/^\d+$/ && $_[1] =~ m/^\d+$/){
      66        
202 5         38 warn "You have called bad_param in an deprecated way. Please consult the documentation\n";
203             #Throw away $dbi_testing_type as we dont use it anymoer
204 5         265 shift;
205             #Throw away $p_num as we dont use it anymore
206 5         6 shift;
207 5         14 $args{p_value} = shift;
208             }else{
209 1         3 %args = @_;
210             }
211            
212 6 100       17 if($args{sql}){
213 1         2 push( @{ $self->{methods}->{bind_param}->{sqls}->{$args{sql}}->{bad_params}}, $args{p_value});
  1         6  
214 1 50       18 $self->{_regexes}->{$args{sql}} = (ref($args{sql}) eq 'Regexp') ? $args{sql} : qr/\Q$args{sql}\E/;
215             }else{
216 5         7 push( @{ $self->{methods}->{bind_param}->{global_bad_params} }, $args{p_value});
  5         41  
217             }
218            
219 6         41 return 1;
220             }
221              
222             =item set_retval()
223              
224             Method for setting a return value for the specific method.
225            
226             Args:(Keys in a hash)
227             method - The method that should return the provided value
228             retval - The data which should be returned
229             sql (Optional) - Matching sql. The return value will only be
230             returned for the provided method if the sql matches
231             a regex compiled by using this string
232              
233             Returnvalues:
234             On success: 1
235             On failure: undef
236            
237             Example usage:
238            
239             #fetchrow_hashref will shift one hashref from the list each time its called if the sql matches the sql provided, this will happend
240             #until the return list is empty.
241             $inst->set_retval( method => 'fetchrow_hashref',
242             retval => [ { letter => 'a' }, { letter => 'b' }, { letter => 'c' } ],
243             sql => 'select * from letters' )
244            
245             #execute will default return undef
246             $inst->set_retval( method => 'execute', retval => undef)
247            
248             #Execute will return 10 for sql 'select * from cars'
249             $inst->set_retval( method => 'execute', retval => undef);
250             $inst->set_retval( method => 'execute', retval => 10, sql => 'select * from cars');
251            
252             =cut
253              
254             sub set_retval{
255 146     146 1 23646 my ($self, %args) = @_;
256            
257 146         188 my $method = $args{method};
258 146 100       327 my $sql = $args{sql} if $args{sql};
259            
260 146 100       254 unless($method){
261 1         15 warn "No method provided\n";
262 1         50 return;
263             }
264            
265 145 100       265 if(ref($method)){
266 1         8 warn "Parameter method must be a scalar string\n";
267 1         35 return;
268             }
269              
270 144 100 100     558 if($sql && (ref($sql) && ref($sql) ne 'Regexp')){
      66        
271 1         8 warn "Parameter SQL must be a scalar string or a precompiled regex\n";
272 1         37 return;
273             }
274            
275 143 100       275 unless( exists $args{retval} ){
276 1         8 warn "No retval provided\n";
277 1         35 return;
278             }
279            
280 142 100       505 $self->{methods}->{$method} = {} if !$self->{methods}->{$method};
281            
282 142 100       257 if($sql){
283 57         559 $self->{methods}->{$method}->{sqls}->{$sql}->{retval} = Clone::clone($args{retval});
284 57 50       167 $self->{methods}->{$method}->{sqls}->{$sql}->{errstr} = $args{errstr} if $args{errstr};
285 57 50       134 $self->{methods}->{$method}->{sqls}->{$sql}->{err} = $args{err} if $args{err};
286 57 100       256 $self->{_regexes}->{$sql} = (ref($sql) eq 'Regexp') ? $sql : qr/\Q$sql\E/;
287             }else{
288 85         501 $self->{methods}->{$method}->{default}->{retval} = Clone::clone($args{retval});
289 85 100       156 $self->{methods}->{$method}->{default}->{errstr} = $args{errstr} if $args{errstr};
290 85 100       137 $self->{methods}->{$method}->{default}->{err} = $args{err} if $args{err};
291             }
292 142         357 return 1;
293             }
294              
295             =item set_inout_value()
296              
297             Special method for handling inout params.
298             In this method you can provided the value that the inout param should have
299             after execute is called.
300            
301             Args:
302             $sql - The sql that this rule should apply for
303             $p_num - The parameter number of the inout parameter
304             $value - The value that the inout parameter should have after execute
305            
306             Returns:
307             On success: 1
308             On failure: undef
309            
310             Example:
311            
312            
313              
314             =cut
315              
316             sub set_inout_value{
317 5     5 1 1310 my ($self, $sql, $p_num, $value) = @_;
318            
319 5 100 66     33 if(!$sql || ref($sql)){
320 1         12 warn "Parameter SQL must be a scalar string\n";
321 1         53 return;
322             }
323 4 100       16 if($p_num !~ m/^\d+$/){
324 1         7 warn "Parameter p_num must be numeric\n";
325 1         33 return;
326             }
327            
328 3         7 $self->{inoutvalues}->{$sql}->{$p_num} = $value;
329 3         5 return 1;
330             }
331              
332             =back
333              
334             =head1 PRIVATE INTERFACE
335              
336             Methods used by the package internally. Should not be called from an external package.
337              
338             =over 4
339              
340             =item _clear_dbi_err_errstr()
341              
342             Helper method used by the fake DBI::st and DBI::db to clear out
343             the $obj->{err} and $obj->{errstr} on each method call.
344            
345             Should not be called from an external script\package.
346              
347             =cut
348              
349             sub _clear_dbi_err_errstr{
350 394     394   405 my ($self, $obj) = @_;
351            
352 394         588 $obj->{errstr} = undef;
353 394         392 $obj->{err} = undef;
354 394         333 $DBI::errstr = undef;
355 394         287 $DBI::err = undef;
356 394         454 return 1;
357             }
358              
359             =item _set_dbi_err_errstr()
360              
361             Helper method used by the fake DBI::st and DBI::db to set the
362             $obj->{err}, $obj->{errstr}, $DBI::err and $DBI::errstr.
363             This method also handles RaiseError and PrintError attributes.
364            
365             Args:
366             $obj - Instance of DBI::st or DBI::db
367             %args - A hash with the following keys:
368             err - The numeric error code to be set
369             errstr - The user friendly DBI error message.
370            
371             Returns:
372             On success : 1
373             On failure : undef
374              
375             =cut
376              
377             sub _set_dbi_err_errstr{
378 66     66   196 my ($self, $obj, %args) = @_;
379 66 100       235 if($args{err}){
380 21         18 $DBI::err = $args{err};
381 21         19 $obj->{err} = $args{err};
382             }
383            
384 66 100       124 if($args{errstr}){
385 21         16 $DBI::errstr = $args{errstr};
386 21         17 $obj->{errstr} = $args{errstr};
387             }
388            
389 66 0 33     198 print $obj->{errstr} . "\n" if $obj->{PrintError} && $obj->{errstr};
390 66 0       126 die( (($obj->{errstr}) ? $obj->{errstr} : '') ) if $obj->{RaiseError};
    50          
391 66         91 return 1;
392             }
393              
394             =item _set_fake_dbi_err_errstr
395              
396             =cut
397              
398             sub _set_fake_dbi_err_errstr{
399 130     130   136 my ($self, $obj) = @_;
400 130         261 my $sql = $obj->{Statement};
401              
402             #This should be refactored out in a helper method
403 130         659 my @caller = caller(1);
404 130         738 my $method = $caller[3];
405            
406 130         477 $method =~ s/Test::MockDBI::(St|Db)::_dbi_//;
407              
408             #No special return value is set for this method
409 130 50       326 return if !exists($self->{methods}->{$method});
410            
411            
412             #Search to see if the sql has a specific
413 130 50       197 if($sql){
414 130         113 foreach my $key (keys %{$self->{methods}->{$method}->{sqls}}){
  130         357  
415             #This introduces the bug that the first hit will be the one used.
416             #This is done to be complient with the regex functionality in the earlier versions
417             #of Test::MockDBI
418 47 100       196 if( $sql =~ $self->{_regexes}->{$key}){
419             $self->_set_dbi_err_errstr($obj,
420             err => $self->{methods}->{$method}->{sqls}->{$key}->{err},
421             errstr => $self->{methods}->{$method}->{sqls}->{$key}->{errstr}
422 45         196 );
423 45         123 return 1;
424             }
425             }
426             }
427             #If $sql is not or we have no matching sql we return the default if it is set
428 85 50 66     186 if(exists $self->{methods}->{$method}->{default}->{err} && exists $self->{methods}->{$method}->{default}->{errstr}){
429             $self->_set_dbi_err_errstr($obj,
430             err => $self->{methods}->{$method}->{default}->{err},
431 17         32 errstr => $self->{methods}->{$method}->{default}->{errstr});
432 17         30 return 1;
433             }
434              
435 68         141 return ;
436             }
437              
438             =item _has_inout_value()
439              
440             Helper method used by the DBI::db and DBI::st packages.
441             The method searches to see if there is specified a value for a
442             inout variable.
443            
444             If called in SCALAR context it return 1/undef based on if the
445             parameter bound as $p_num has a predefined return value set.
446            
447             If called in LIST context the method returns and array with
448             1/undef in position 0 which indicates the same as when the method
449             is called in SCALAR context. The second element of the list is the
450             value that should be applied to the inout parameter.
451              
452             =cut
453              
454             sub _has_inout_value{
455 3     3   4 my ($self, $sql, $p_num) = @_;
456            
457 3         1 foreach my $key (keys %{ $self->{inoutvalues} }){
  3         6  
458 3 50       28 if( $sql =~ m/\Q$key\E/ms){
459 3 50       5 if($self->{inoutvalues}->{$key}->{$p_num}){
460 3 50       10 return (wantarray) ? (1, $self->{inoutvalues}->{$key}->{$p_num}) : 1;
461             }
462             }
463             }
464 0         0 return;
465             }
466              
467             =item _has_fake_retval()
468            
469             Method for identifing if a method has a predefined return value set.
470             If the SQL parameter is provided
471             this will have precedence over the default value.
472            
473             If the method is called in SCALAR context it will return 1\undef based on
474             if the method has a predefined return value set.
475            
476             If the method is called in LIST context it will return a list with 1/undef at
477             index 0 which indicates the same as when called in SCALAR context. index 1 will
478             contain a reference to the actual return value that should be returned by the method.
479             This value may be undef.
480            
481             =cut
482              
483             sub _has_fake_retval{
484 431     431   446 my ($self, $sql) = @_;
485 431         1574 my @caller = caller(1);
486 431         4078 my $method = $caller[3];
487            
488 431         2019 $method =~ s/Test::MockDBI(::(St|Db))?::_dbi_//;
489            
490             #No special return value is set for this method
491 431 100       1697 return if !exists($self->{methods}->{$method});
492            
493            
494             #Search to see if the sql has a specific
495 176 100       311 if($sql){
496 149         153 foreach my $key (keys %{$self->{methods}->{$method}->{sqls}}){
  149         611  
497             #This introduces the bug that the first hit will be the one used.
498             #This is done to be complient with the regex functionality in the earlier versions
499             #of Test::MockDBI
500             # if( ( ($key =~ m/^\(\?\^:/ && $sql =~ $instance->{legacy_regex}->{$key}) || $sql =~ m/\Q$key\E/ms ) &&
501             # exists $self->{methods}->{$method}->{sqls}->{$key}->{retval}){
502            
503             # to handle old and new versions of PERL
504 73 100       209 my $modifiers = ($key =~ /\Q(?^/) ? "^" : "-xism";
505            
506 73 100 66     504 if( $sql =~ $self->{_regexes}->{$key} &&
507             exists $self->{methods}->{$method}->{sqls}->{$key}->{retval}){
508            
509 45 50       206 if(wantarray()){
510 45         263 return (1, $self->{methods}->{$method}->{sqls}->{$key}->{retval});
511             }else{
512 0         0 return 1;
513             }
514             }
515             }
516             }
517             #If $sql is not or we have no matching sql we return the default if it is set
518 131 100       312 if(exists $self->{methods}->{$method}->{default}->{retval}){
519 88 50       370 return (wantarray()) ? (1, $self->{methods}->{$method}->{default}->{retval}) : undef;
520             }
521            
522 43         116 return;
523             }
524              
525             =item _is_bad_bind_param()
526            
527             Method for identifing if a bind parameters value is predefined as unwanted.
528             The configuration for the provided SQL will have precedence over the default configured behaviour.
529            
530             When called it will return 1\undef based on
531             if the provided value should make the bind_param method fail.
532            
533             =cut
534              
535             sub _is_bad_bind_param{
536 32     32   38 my ($self, $sql, $param) = @_;
537 32         105 my @caller = caller(1);
538 32         181 my $method = $caller[3];
539            
540 32         118 $method =~ s/Test::MockDBI::(St|Db)::_dbi_//;
541            
542 32         41 foreach my $key (keys %{ $self->{methods}->{$method}->{sqls} }){
  32         77  
543             #This introduces the bug that the first hit will be the one used.
544             #This is done to be complient with the regex functionality in the earlier versions
545             #of Test::MockDBI
546            
547 4 50       14 if( $sql =~ $self->{_regexes}->{$key} ){
548             #If no bad params is set for this sql do nothing and continue the loop.
549 4 50 33     19 if($self->{methods}->{$method}->{sqls}->{$key}->{bad_params} &&
550             ref($self->{methods}->{$method}->{sqls}->{$key}->{bad_params}) eq 'ARRAY'){
551            
552 4         5 foreach my $bad_param ( @{ $self->{methods}->{$method}->{sqls}->{$key}->{bad_params} }){
  4         7  
553 4 50 33     19 if(Scalar::Util::looks_like_number($param) && Scalar::Util::looks_like_number($bad_param)){
554 4 100       20 return 1 if $param == $bad_param;
555             }
556 2 50       7 return 1 if $param eq $bad_param;
557             }
558             }
559             }
560             }
561            
562 30 100 66     120 if(exists $self->{methods}->{$method}->{global_bad_params} && ref($self->{methods}->{$method}->{global_bad_params}) eq 'ARRAY'){
563 10         10 foreach my $bad_param ( @{ $self->{methods}->{$method}->{global_bad_params} }){
  10         24  
564 10 100 100     73 if(Scalar::Util::looks_like_number($param) && Scalar::Util::looks_like_number($bad_param)){
565 1 50       3 return 1 if $param == $bad_param;
566             }
567 10 100       130 return 1 if $param eq $bad_param;
568             }
569             }
570 27         89 return;
571             }
572              
573             =back
574              
575             =head1 CLASS INTERFACE
576              
577             =over 4
578              
579             =item get_instance()
580              
581             Method for retrieving the current Test::MockDBI instance
582            
583             =cut
584              
585             sub get_instance{
586 40     40 1 14763 return $instance;
587             }
588              
589             =back
590              
591             =cut
592              
593             ####################################
594             #
595             # Mocked DBI API
596             # (Method used to mock the DBI package's methods)
597             #
598             ####################################
599              
600             =pod _dbi__concat_hash_sorted
601              
602             This is basically a copy\paste from the DBI package itself.
603             The method is used inside the prepare_cached method
604              
605             =cut
606              
607             sub _dbi__concat_hash_sorted {
608 6     6   7 my ( $hash_ref, $kv_separator, $pair_separator, $use_neat, $num_sort ) = @_;
609             # $num_sort: 0=lexical, 1=numeric, undef=try to guess
610              
611 6 50       10 return undef unless defined $hash_ref;
612 6 50       13 die "hash is not a hash reference" unless ref $hash_ref eq 'HASH';
613 6         7 my $keys = DBI::_get_sorted_hash_keys($hash_ref, $num_sort);
614 6         6 my $string = '';
615 6         7 for my $key (@$keys) {
616 3 50       6 $string .= $pair_separator if length $string > 0;
617 3         4 my $value = $hash_ref->{$key};
618 3 50       5 if ($use_neat) {
619 0         0 $value = DBI::neat($value, 0);
620             }
621             else {
622 3 50       6 $value = (defined $value) ? "'$value'" : 'undef';
623             }
624 3         7 $string .= $key . $kv_separator . $value;
625             }
626 6         19 return $string;
627             }
628              
629             =pod _dbi__get_sorted_hash_keys
630              
631             This is basically a copy\paste from the DBI package itself.
632             The method is used inside the prepare_cached method
633              
634             =cut
635              
636             sub _dbi__get_sorted_hash_keys {
637 6     6   6 my ($hash_ref, $num_sort) = @_;
638 6 50       10 if (not defined $num_sort) {
639 0         0 my $sort_guess = 1;
640             $sort_guess = (not DBI::looks_like_number($_)) ? 0 : $sort_guess
641 0 0       0 for keys %$hash_ref;
642 0         0 $num_sort = $sort_guess;
643             }
644            
645 6         11 my @keys = keys %$hash_ref;
646 50     50   307 no warnings 'numeric';
  50         70  
  50         36826  
647             my @sorted = ($num_sort)
648 6 0       13 ? sort { $a <=> $b or $a cmp $b } @keys
  0 50       0  
649             : sort @keys;
650 6         9 return \@sorted;
651             }
652              
653             =pod _dbi_looks_like_number
654              
655             This is basically a copy\paste from the DBI package itself.
656             The method is used inside the prepare_cached method
657              
658             =cut
659              
660             sub _dbi_looks_like_number {
661 0     0   0 my @new = ();
662 0         0 for my $thing(@_) {
663 0 0 0     0 if (!defined $thing or $thing eq '') {
664 0         0 push @new, undef;
665             }
666             else {
667 0 0       0 push @new, ($thing =~ /^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/) ? 1 : 0;
668             }
669             }
670 0 0       0 return (@_ >1) ? @new : $new[0];
671             }
672              
673             =pod _dbi_connect
674              
675             Mocked DBI->connect method.
676            
677             The method takes the same arguments as the usual DBI->connect method.
678             It returns a $dbh which has ref DBI::db
679            
680             =cut
681              
682             sub _dbi_connect{
683 56     56   10968 my ($self, $dsn, $user, $pass, $attr) = @_;
684            
685 56         113 my $statement = 'CONNECT TO $dsn AS $user WITH $pass';
686            
687 56         232 my ($status, $retval) = $instance->_has_fake_retval($statement);
688 56 100       164 if($status){
689 3 100       9 if(ref($retval) eq 'CODE'){
690 1         2 return $retval->();
691             }
692 2         5 return $retval;
693             }
694            
695 53         1333 my $object = bless({
696             AutoCommit => 1,
697             Driver => undef,
698             Name => undef,
699             Statement => $statement,
700             RowCacheSize => undef,
701             Username => undef,
702            
703             #Common
704             Warn => undef,
705             Active => undef,
706             Executed => undef,
707             Kids => 0,
708             ActiveKids => undef,
709             CachedKids => undef,
710             Type => 'db',
711             ChildHandles => [],
712             CompatMode => undef,
713             InactiveDestroy => undef,
714             AutoInactiveDestroy => undef,
715             PrintWarn => undef,
716             PrintError => undef,
717             RaiseError => undef,
718             HandleError => undef,
719             HandleSetErr => undef,
720             ErrCount => undef,
721             ShowErrorStatement => undef,
722             TraceLevel => undef,
723             FetchHashKeyName => undef,
724             ChopBlanks => undef,
725             LongReadLen => undef,
726             LongTruncOk => undef,
727             TaintIn => undef,
728             TaintOut => undef,
729             Taint => undef,
730             Profile => undef,
731             ReadOnly => undef,
732             Callbacks => undef,
733             }, "DBI::db");
734            
735 53         98 foreach my $key (keys %{ $attr }){
  53         187  
736 9 50       41 $object->{$key} = $attr->{$key} if(exists($object->{$key}));
737             }
738            
739 53         180 return $object;
740            
741             }
742              
743             ##########################################################
744             #
745             # DEPRECATED OLD INTERFACE
746             #
747             ###########################################################
748             sub set_retval_array{
749 10     10 0 1335 warn 'set_retval_array is deprecated. Please use $instance->set_retval instead' . "\n";
750 10         471 my ($self, $dbi_testing_type, $matching_sql, @retval) = @_;
751            
752 10         166 my $regex = qr/$matching_sql/;
753            
754 10 100       46 if(ref($retval[0]) eq 'CODE'){
755 2         10 return $instance->set_retval( method => 'fetchrow_arrayref', sql => $regex, retval => $retval[0]);
756             }else{
757 8         51 return $instance->set_retval( method => 'fetchrow_arrayref', sql => $regex, retval => [ \@retval ]);
758             }
759             }
760             sub set_retval_scalar{
761 17     17 0 4769 warn 'set_retval_scalar is deprecated. Please use $instance->set_retval instead' . "\n";
762 17         769 my ($self, $dbi_testing_type, $matching_sql, $retval) = @_;
763            
764 17         57 my @methods = qw(fetchall_arrayref fetchrow_arrayref fetchall_hashref fetchrow_hashref);
765              
766 17         246 my $regex = qr/$matching_sql/;
767              
768             #try to find out if the $retval is an arrayref only, or an arrayref of arrayref
769             # or arrayref of hashrefs
770 17 100       73 if(ref($retval) eq 'ARRAY'){
    100          
771 10         20 my $item = $retval->[0];
772            
773 10 100       65 if(ref($item) eq 'ARRAY'){
    50          
    50          
774             #We most likely have an arrayref of arrayrefs
775             #it should be applied to fetchall_arrayref and fetchrow_arrayref
776 2         9 $instance->set_retval( method => 'fetchall_arrayref', sql => $regex, retval => $retval);
777 2         6 $instance->set_retval( method => 'fetchrow_arrayref', sql => $regex, retval => $retval);
778             }elsif(ref($item) eq 'HASH'){
779             #We most likely have an arrayref of hashrefs
780             #it should be applied to fetchall_hashrefref and fetchrow_hashref
781 0         0 $instance->set_retval( method => 'fetchall_hashref', sql => $regex, retval => $retval);
782 0         0 $instance->set_retval( method => 'fetchrow_hashref', sql => $regex, retval => $retval);
783             }elsif(!ref($item)){
784             #We only have 1 arrayref with values. This was used in the old Test::MockDBI tests
785             #It was passed because you only called for instance fetchrow_arrayref once
786             #We will wrap it in an array and hope for the best
787 8         38 $instance->set_retval( method => 'fetchrow_arrayref', sql => $regex, retval => [$retval]);
788             }else{
789             #We dont know, set the same retval for EVERYONE!
790 0         0 foreach my $method ( @methods ){
791 0         0 $instance->set_retval( method => $method, sql => $regex, retval => $retval);
792             }
793             }
794            
795             }elsif(ref($retval) eq 'HASH'){
796 1         5 $instance->set_retval( method => 'fetchrow_hashref', sql => $regex, retval => [$retval]);
797             }else{
798             #We dont know, set the same retval for EVERYONE!
799 6         14 foreach my $method ( @methods ){
800 24         47 $instance->set_retval( method => $method, sql => $regex, retval => $retval);
801             }
802             }
803 17         81 return 1;
804             }
805             sub set_rows{
806 4     4 0 292 warn 'set_rows is deprecated. Please use $instance->set_retval instead' . "\n";
807 4         209 my ($self, $dbi_testing_type, $matching_sql, $rows) = @_;
808            
809 4         54 my $regex = qr/$matching_sql/;
810            
811 4         22 return $instance->set_retval( method => 'rows', sql => $regex, retval => $rows );
812             }
813              
814             sub set_errstr{
815 0     0 0   warn "set_errstr is deprecated. Please use $instance->set_retval instead \n";
816 0           return;
817             }
818             sub _is_bad_param{
819 0     0     warn "_is_bad_param is deprecated and no longer functional. It allways returns 1\n";
820 0           return 1;
821             }
822             sub set_dbi_test_type{
823 0     0 0   warn "set_dbi_test_type is deprecated. Does nothing!\n";
824 0           return 1;
825             }
826             sub get_dbi_test_type{
827 0     0 0   warn "get_dbi_test_type is deprecated. Does nothing!\n";
828 0           return 1;
829             }
830              
831             =head1 AUTHOR
832              
833             Mark Leighton Fisher,
834             Emark-fisher@fisherscreek.comE
835              
836             Minor modifications (version 0.62 onwards) by
837             Andreas Faafeng
838             Eaff@cpan.orgE
839              
840             =head1 COPYRIGHT
841              
842             Copyright 2004, Fisher's Creek Consulting, LLC. Copyright
843             2004, DeepData, Inc.
844              
845             =head1 LICENSE
846              
847             This code is released under the same licenses as Perl
848             itself.
849              
850             =cut
851              
852             1;