Beefy Boxes and Bandwidth Generously Provided by pair Networks
No such thing as a small change
 
PerlMonks  

Re: Mocking files for reading

by mayaTheCat (Scribe)
on Sep 04, 2007 at 22:36 UTC ( [id://637034]=note: print w/replies, xml ) Need Help??


in reply to Mocking files for reading

Thanks to all of you for your enlightening replies.

With your replies I realized that I have somehow neglected "tie" so far. Shame on me :)

My aim is to write a module which simply helps testing reading or writing to files, without actually touching the file system.

With that in my mind, it looks like in-memory file is the answer. Besides, when I play with it I concluded that the in-memory file mechanism is something like a predefined tied filehandle.

I modified my module and wanna share with you: (As you can see, since the in-memory file mechanism is so powerful, I can also mock files for writing; thus I changed the name of the module)

package Test::MockFile::Light; use strict; use Carp; # --- my %file; sub define_file_mocker { my ($name, $content) = @_; $content ||= ''; $file{$name} = $content; } sub undefine_file_mocker { my ($name, $content) = @_; delete $file{$name}; } # --- sub import { my ($class, %arg) = @_; my $package = caller; _export_functions_to($package); my $module = defined $arg{module} ? $arg{module} : $package; _override_open_builtin_for($module); } # --- sub _export_functions_to { my ($package) = @_; no strict 'refs'; *{"$package\::define_file_mocker"} = \&define_file_mocker; *{"$package\::undefine_file_mocker"} = \&undefine_file_mocker; } # --- sub _override_open_builtin_for { my ($module) = @_; my $mode_and_name_parser = qr/ ^ \s* (|<|>|>>|\+<|\+>|\+>>) # the mode \s* (\w.*?) # the file name \s* $ /x; no strict 'refs'; *{"$module\::open"} = sub (\[*$]$;$) { my ($fh, $mode, $name) = @_; $name ||= ''; my $compound = "$mode $name"; if ($compound =~ $mode_and_name_parser) { $mode = $1 || '<'; $name = $2; } else { croak 'Unexpected open() parameters for file mocking'; } if ($mode eq '<' && ! defined $file{$name}) { $! = 2; return 0; } return open $$fh, $mode, \$file{$name}; }; } # --- 1;
A sample usage of the module can be as follows:
package Foo::Bar; sub process { my ($class, $file_name) = @_; my $sum = 0; open my $fh, $file_name; while (<$fh>) { chomp; $sum += $_; } close $fh; return $sum; } 1;
... and then,
use Test::More tests => 3; use Test::MockFile::Light module => 'Foo::Bar'; use_ok('Foo::Bar'); my $file_name = 'data.txt'; my $content = join("\n", 1..5); define_file_mocker($file_name, $content); can_ok(Foo::Bar, 'process'); is(Foo::Bar->process($file_name), 15, 'unexpected sum');
I plan to put it on CPAN. Any comments are welcome.

Thanks again,
Oguz

---------------------------------
life is ... $mutation = sub { $_[0] =~ s/(.)/rand()<0.1?1-$1:$1/ge };

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://637034]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others having an uproarious good time at the Monastery: (3)
As of 2024-04-19 05:35 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found