1package Plucene::TestCase;
2
3=head1 NAME
4
5Plucene::TestCase - Handy functions when testing Plucene
6
7=head1 SYNOPSIS
8
9	use Test::More tests => 10;
10	use Plucene::TestCase;
11
12	new_index {
13		add_document( foo => "bar" );
14	};
15
16	re_index {
17		add_document( foo => "baz" );
18	}
19
20	with_reader {
21		$READER->whatever;
22	}
23
24	my $hits = search("foo:ba*");
25
26=head1 EXPORTS
27
28=cut
29
30use strict;
31use warnings;
32
33use base 'Exporter';
34
35use Plucene::Index::Reader;
36use Plucene::Index::Writer;
37use Plucene::Document;
38use Plucene::Document::Field;
39use Plucene::Analysis::SimpleAnalyzer;
40use Plucene::QueryParser;
41use Plucene::Search::IndexSearcher;
42
43our (@EXPORT, $DIR, $DEBUG, $WRITER, $READER, $ANALYZER);
44@EXPORT = qw($DIR $WRITER $READER $ANALYZER new_index re_index
45	with_reader add_document search);
46
47$ANALYZER = "Plucene::Analysis::SimpleAnalyzer";
48
49=over 3
50
51=item C<$DIR>
52
53A directory which is created for the purposes of this test, in which the
54index will be placed. It will normally be cleaned up at the end of the
55test, unless C<$Plucene::TestCase::DEBUG> is set to allow you to peruse
56the entrails.
57
58=cut
59
60use File::Temp qw(tempdir);
61$DIR = tempdir(CLEANUP => !$DEBUG);
62
63=item C<$WRITER>
64
65A variable holding the current C<Index::Writer> object, if there is one.
66
67=item C<$READER>
68
69A variable holding the current C<Index::Reader> object, if there is one.
70
71=item C<$ANALYZER>
72
73A variable holding the class name of the desired C<Analysis::Analyzer>
74class.
75
76=item new_index BLOCK (Analyzer)
77
78Create a new index, and do the following stuff in the block before
79closing the index writer. C<$WRITER> is set for the duration of the
80block.
81
82The optional parameter should be the class name of the analyzer to use;
83if not specified, the value from C<$ANALYZER>, which in turn defaults to
84C<Plucene::Analysis::SimpleAnalyzer>, will be used.
85
86=cut
87
88sub new_index(&;$) {
89	my ($block, $analyzer) = @_;
90	$analyzer ||= $ANALYZER;
91
92	# UNIVERSAL::require loads UNIVERSAL->import, which won't do.
93	eval "require $analyzer";
94	die "Couldn't require $analyzer" if $@;
95	$WRITER = Plucene::Index::Writer->new($DIR, $analyzer->new, 1);
96	$block->();
97	undef $WRITER;
98}
99
100=item re_index BLOCK (Analyzer)
101
102Same as C<new_index>, but doesn't create a new index, rather re-uses an
103old one.
104
105=cut
106
107sub re_index(&;$) {
108	my ($block, $analyzer) = @_;
109	$analyzer ||= $ANALYZER;
110	eval "require $analyzer";
111	die "Couldn't require $analyzer" if $@;
112	$WRITER = Plucene::Index::Writer->new($DIR, $analyzer->new, 0);
113	$block->();
114	undef $WRITER;
115}
116
117=item add_document( field1 => value1, ...)
118
119Add a new document to the index, with the given fields and values
120
121=cut
122
123sub add_document {
124	my @args = @_;
125	my $doc  = Plucene::Document->new;
126	while (my ($k, $v) = splice(@args, 0, 2)) {
127		$doc->add(Plucene::Document::Field->Text($k, $v));
128	}
129	$WRITER->add_document($doc);
130}
131
132=item with_reader BLOCK
133
134Opens an index reader in C<$READER> and runs the block.
135
136=cut
137
138sub with_reader (&) {
139	$READER = Plucene::Index::Reader->open($DIR);
140	shift->();
141	$READER->close;
142	undef $READER;
143}
144
145=item search
146
147Searches for the query given. If any fields are not specified, they will
148be assumed to be the default C<text>. Returns a C<Plucene::Search::Hits>
149object. The value of C<$ANALYZER> will be used to construct an analyzer
150for the query string.
151
152=cut
153
154sub search {
155	eval "require $ANALYZER";
156	my $parser = Plucene::QueryParser->new({
157			analyzer => $ANALYZER->new(),
158			default  => "text"
159		});
160	Plucene::Search::IndexSearcher->new($DIR)->search($parser->parse(shift));
161}
162
1631;
164