use strict;
use warnings;
use Test::More;
use Test::Exception;
use MongoDB;
use MongoDB::OID;
use MongoDB::Code;
use MongoDB::Timestamp;
use DateTime;
use JSON;
my $conn;
eval {
my $host = "localhost";
if (exists $ENV{MONGOD}) {
$host = $ENV{MONGOD};
}
$conn = MongoDB::Connection->new(host => $host, ssl => $ENV{MONGO_SSL});
};
if ($@) {
plan skip_all => $@;
}
else {
plan tests => 55;
}
my $db = $conn->get_database('x');
my $coll = $db->get_collection('y');
$coll->drop;
my $id = MongoDB::OID->new;
isa_ok($id, 'MongoDB::OID');
is($id."", $id->value);
# OIDs created in time-ascending order
{
my $ids = [];
for (0..9) {
push @$ids, new MongoDB::OID;
sleep 1;
}
for (0..8) {
ok((@$ids[$_]."") lt (@$ids[$_+1].""));
}
my $now = DateTime->now;
$id = MongoDB::OID->new;
is($now->epoch, $id->get_time);
}
# creating ids from an existing value
{
my $value = "012345678901234567890123";
my $id = MongoDB::OID->new(value => $value);
is($id->value, $value);
my $id_orig = MongoDB::OID->new;
my $id_copy = MongoDB::OID->new(value => $id_orig->value);
is($id_orig->value, $id_copy->value);
}
#regexes
$coll->insert({'x' => 'FRED', 'y' => 1});
$coll->insert({'x' => 'bob'});
$coll->insert({'x' => 'fRed', 'y' => 2});
my $freds = $coll->query({'x' => qr/fred/i})->sort({'y' => 1});
is($freds->next->{'x'}, 'FRED', 'case insensitive');
is($freds->next->{'x'}, 'fRed', 'case insensitive');
ok(!$freds->has_next, 'bob doesn\'t match');
my $fred = $coll->find_one({'x' => qr/^F/});
is($fred->{'x'}, 'FRED', 'starts with');
# saving/getting regexes
$coll->drop;
$coll->insert({"r" => qr/foo/i});
my $obj = $coll->find_one;
ok("foo" =~ $obj->{'r'}, 'matches');
SKIP: {
skip "regex flags don't work yet with perl 5.8", 1 if $] =~ /5\.008/;
ok("FOO" =~ $obj->{'r'}, 'this won\'t pass with Perl 5.8');
}
ok(!("bar" =~ $obj->{'r'}), 'not a match');
# date
$coll->drop;
my $now = DateTime->now;
$coll->insert({'date' => $now});
my $date = $coll->find_one;
is($date->{'date'}->epoch, $now->epoch);
is($date->{'date'}->day_of_week, $now->day_of_week);
my $past = DateTime->from_epoch('epoch' => 1234567890);
$coll->insert({'date' => $past});
$date = $coll->find_one({'date' => $past});
is($date->{'date'}->epoch, 1234567890);
# minkey/maxkey
$coll->drop;
my $min = bless {}, "MongoDB::MinKey";
my $max = bless {}, "MongoDB::MaxKey";
$coll->insert({min => $min, max => $max});
my $x = $coll->find_one;
isa_ok($x->{min}, 'MongoDB::MinKey');
isa_ok($x->{max}, 'MongoDB::MaxKey');
# tie::ixhash
{
$coll->remove;
my %test;
tie %test, 'Tie::IxHash';
$test{one} = "on";
$test{two} = 2;
$coll->insert(\%test);
my $doc = $coll->find_one;
is($doc->{'one'}, 'on');
is($doc->{'two'}, 2);
}
# binary
{
$coll->remove;
my $invalid = "\xFE";
$coll->insert({"bin" => \$invalid});
my $one = $coll->find_one;
is($one->{'bin'}, "\xFE");
}
# 64-bit ints
{
use bigint;
$coll->remove;
my $x = 2 ** 34;
$coll->save({x => $x});
my $result = $coll->find_one;
is($result->{'x'}, 17179869184);
$coll->remove;
$x = (2 ** 34) * -1;
$coll->save({x => $x});
$result = $coll->find_one;
is($result->{'x'}, -17179869184);
$coll->remove;
$coll->save({x => 2712631400});
$result = $coll->find_one;
is($result->{'x'}, 2712631400);
eval {
my $ok = $coll->save({x => 9834590149023841902384137418571984503});
};
ok($@ =~ m/BigInt is too large/);
$coll->remove;
}
# code
{
my $str = "function() { return 5; }";
my $code = MongoDB::Code->new("code" => $str);
my $scope = $code->scope;
is(keys %$scope, 0);
$coll->insert({"code" => $code});
my $ret = $coll->find_one;
my $ret_code = $ret->{code};
$scope = $ret_code->scope;
is(keys %$scope, 0);
is($ret_code->code, $str);
my $x = $db->eval($code);
is($x, 5);
$str = "function() { return name; }";
$code = MongoDB::Code->new("code" => $str,
"scope" => {"name" => "Fred"});
$x = $db->eval($code);
is($x, "Fred");
$coll->remove;
$coll->insert({"x" => "foo", "y" => $code, "z" => 1});
$x = $coll->find_one;
is($x->{x}, "foo");
is($x->{y}->code, $str);
is($x->{y}->scope->{"name"}, "Fred");
is($x->{z}, 1);
$coll->remove;
}
SKIP: {
use Config;
skip "Skipping 64 bit native SV", 1
if ( !$Config{use64bitint} );
$coll->update({ x => 1 }, { '$inc' => { 'y' => 19401194714 } }, { 'upsert' => 1 });
my $result = $coll->find_one;
is($result->{'y'},19401194714,'64 bit ints without Math::BigInt');
}
# oid json
{
my $doc = {"foo" => MongoDB::OID->new};
my $j = JSON->new;
$j->allow_blessed;
$j->convert_blessed;
my $json = $j->encode($doc);
is($json, '{"foo":{"$oid":"'.$doc->{'foo'}->value.'"}}');
}
# timestamp
{
$coll->drop;
my $t = MongoDB::Timestamp->new("sec" => 12345678, "inc" => 9876543);
$coll->insert({"ts" => $t});
my $x = $coll->find_one;
is($x->{'ts'}->sec, $t->sec);
is($x->{'ts'}->inc, $t->inc);
}
# use_boolean
{
$coll->drop;
$MongoDB::BSON::use_boolean = 0;
$coll->insert({"x" => boolean::true, "y" => boolean::false});
my $x = $coll->find_one;
isa_ok($x->{x}, 'SCALAR');
isa_ok($x->{y}, 'SCALAR');
is($x->{x}, 1);
is($x->{y}, 0);
$MongoDB::BSON::use_boolean = 1;
$x = $coll->find_one;
isa_ok($x->{x}, 'boolean');
isa_ok($x->{y}, 'boolean');
is($x->{x}, boolean::true);
is($x->{y}, boolean::false);
}
# unrecognized obj
{
eval {
$coll->insert({"x" => $coll});
};
ok($@ =~ m/type \(MongoDB::Collection\) unhandled/, "can't insert a non-recognized obj: $@");
}
END {
if ($db) {
$db->drop;
}
}