my
$testdb
= get_test_db(build_client());
my
$c
=
$testdb
->get_collection(
'bar'
);
subtest
"realloc"
=>
sub
{
$c
->drop;
my
$long_str
=
"y"
x 8184;
$c
->insert_one({
'text'
=>
$long_str
});
my
$result
=
$c
->find_one;
is(
$result
->{
'text'
},
$long_str
,
'realloc'
);
};
subtest
"id realloc"
=>
sub
{
$c
->drop;
my
$med_str
=
"z"
x 4014;
$c
->insert_one({
'text'
=>
$med_str
,
'id2'
=> MongoDB::OID->new});
my
$result
=
$c
->find_one;
is(
$result
->{
'text'
},
$med_str
,
'id realloc'
);
};
subtest
"types"
=>
sub
{
$c
->drop;
my
$id
=
$c
->insert_one({
"n"
=>
undef
,
"l"
=> 234234124,
"d"
=> 23.23451452,
"b"
=> true,
"a"
=> {
"foo"
=>
"bar"
,
"n"
=>
undef
,
"x"
=> MongoDB::OID->new(
"49b6d9fb17330414a0c63102"
)},
"d2"
=> DateTime->from_epoch(
epoch
=> 1271079861),
"regex"
=>
qr/xtz/
,
"_id"
=> MongoDB::OID->new(
"49b6d9fb17330414a0c63101"
),
"string"
=>
"string"
})->inserted_id;
my
$obj
=
$c
->find_one;
is(
$obj
->{
'n'
},
undef
);
is(
$obj
->{
'l'
}, 234234124);
ok(
abs
(
$obj
->{
'd'
} - 23.23451452) < 1e-6 );
is(
$obj
->{
'b'
}, true);
is(
$obj
->{
'a'
}->{
'foo'
},
'bar'
);
is(
$obj
->{
'a'
}->{
'n'
},
undef
);
isa_ok(
$obj
->{
'a'
}->{
'x'
},
'MongoDB::OID'
);
isa_ok(
$obj
->{
'd2'
},
'DateTime'
);
is(
$obj
->{
'd2'
}->epoch, 1271079861);
ok(
$obj
->{
'regex'
});
isa_ok(
$obj
->{
'_id'
},
'MongoDB::OID'
);
is(
$obj
->{
'_id'
},
$id
);
is(
$obj
->{
'string'
},
'string'
);
};
subtest
"\$MongoDB::BSON::char"
=>
sub
{
local
$MongoDB::BSON::char
=
"="
;
my
$alt_client
= build_client();
my
$alt_c
=
$alt_client
->db(
$testdb
->name)->coll(
$c
->name);
$alt_c
->drop;
$alt_c
->update_one({
x
=> 1}, {
"=inc"
=> {
x
=> 1}}, {
upsert
=> true});
my
$up
=
$c
->find_one;
is(
$up
->{x}, 2);
};
subtest
"\$MongoDB::BSON::char ':'"
=>
sub
{
local
$MongoDB::BSON::char
=
":"
;
my
$alt_client
= build_client();
my
$alt_c
=
$alt_client
->db(
$testdb
->name)->coll(
$c
->name);
$alt_c
->drop;
$alt_c
->insert_many([{
x
=> 1}, {
x
=> 2}, {
x
=> 3}, {
x
=> 4}, {
x
=> 5}]);
my
$cursor
=
$alt_c
->query({
x
=> {
":gt"
=> 2,
":lte"
=> 4}})->
sort
({
x
=> 1});
my
$result
=
$cursor
->
next
;
is(
$result
->{x}, 3);
$result
=
$cursor
->
next
;
is(
$result
->{x}, 4);
ok(!
$cursor
->has_next);
};
subtest
"UTF-8 strings"
=>
sub
{
$c
->drop;
$c
->insert_one({
char
=>
"\xFE"
});
my
$x
=
$c
->find_one;
is(
$x
->{char},
"\xFE"
);
$c
->remove;
my
$valid
=
"\x{8D4B}\x{8BD5}"
;
$c
->insert_one({
char
=>
$valid
});
$x
=
$c
->find_one;
ok(utf8::is_utf8(
$x
->{char}));
is(
length
$x
->{char}, 2);
};
subtest
"bad UTF8"
=>
sub
{
my
@bad
= (
"\xC0\x80"
,
"\xC0\xAF"
,
"\xE0\x80\x80"
,
"\xF0\x80\x80\x80"
,
"\xE0\x83\xBF"
,
"\xF0\x80\x83\xBF"
,
"\xF0\x80\xA3\x80"
,
);
for
my
$bad_utf8
(
@bad
) {
my
$label
=
"0x"
.
unpack
(
"H*"
,
$bad_utf8
);
Encode::_utf8_on(
$bad_utf8
);
like(
exception {
$c
->insert_one({
char
=>
$bad_utf8
}) },
qr/Invalid UTF-8 detected while encoding/
,
"invalid UTF-8 throws an error inserting $label"
);
}
};
subtest
"undefined"
=>
sub
{
my
$err
=
$testdb
->run_command([
getLastError
=> 1]);
ok(!
defined
$err
->{err},
"undef"
);
};
subtest
"circular references"
=>
sub
{
my
$q
= {};
$q
->{
'q'
} =
$q
;
eval
{
$c
->insert_one(
$q
);
};
ok($@ =~ /circular
ref
/);
my
%test
;
tie
%test
,
'Tie::IxHash'
;
$test
{t} = \
%test
;
eval
{
$c
->insert_one(\
%test
);
};
ok($@ =~ /circular
ref
/);
my
$tie
= Tie::IxHash->new;
$tie
->Push(
"t"
=>
$tie
);
eval
{
$c
->insert_one(
$tie
);
};
ok($@ =~ /circular
ref
/);
};
subtest
"no . in key names"
=>
sub
{
eval
{
$c
->insert_one({
"x.y"
=>
"foo"
});
};
like($@,
qr/documents for storage cannot contain/
,
"insert"
);
eval
{
$c
->insert_one({
"x.y"
=>
"foo"
,
"bar"
=>
"baz"
});
};
like($@,
qr/documents for storage cannot contain/
,
"insert"
);
eval
{
$c
->insert_one({
"bar"
=>
"baz"
,
"x.y"
=>
"foo"
});
};
like($@,
qr/documents for storage cannot contain/
,
"insert"
);
eval
{
$c
->insert_one({
"bar"
=> {
"x.y"
=>
"foo"
}});
};
like($@,
qr/documents for storage cannot contain/
,
"insert"
);
TODO: {
local
$TODO
=
"insert_many doesn't check for nested keys"
;
eval
{
$c
->insert_many([{
"x"
=>
"foo"
}, {
"x.y"
=>
"foo"
}, {
"y"
=>
"foo"
}]);
};
like($@,
qr/documents for storage cannot contain/
,
"batch insert"
);
eval
{
$c
->insert_many([{
"x"
=>
"foo"
}, {
"foo"
=> [
"x"
, {
"x.y"
=>
"foo"
}]}, {
"y"
=>
"foo"
}]);
};
like($@,
qr/documents for storage cannot contain/
,
"batch insert"
);
}
};
subtest
"empty key name"
=>
sub
{
eval
{
$c
->insert_one({
""
=>
"foo"
});
};
ok($@ =~ /empty key name/);
};
has
'name'
=> (
is
=>
'rw'
,
isa
=>
'Str'
);
has
'age'
=> (
is
=>
'rw'
,
isa
=>
'Int'
);
has
'size'
=> (
is
=>
'rw'
,
isa
=>
'Num'
);
subtest
"Person object"
=>
sub
{
$c
->drop;
my
$p
= Person->new(
name
=>
'jay'
,
age
=>22 );
$c
->save(
$p
);
my
$person
=
$c
->find_one;
is(
$person
->{
'age'
}, 22,
"roundtrip number"
);
};
subtest
"warn on floating timezone"
=>
sub
{
my
$warned
= 0;
local
$SIG
{__WARN__} =
sub
{
if
(
$_
[0] =~ /floating/) {
$warned
= 1; }
else
{
warn
(
@_
); } };
my
$date
= DateTime->new(
year
=> 2010,
time_zone
=>
"floating"
);
$c
->insert_one({
"date"
=>
$date
});
is(
$warned
, 1,
"warn on floating timezone"
);
};
subtest
"epoch time"
=>
sub
{
my
$date
= DateTime->from_epoch(
epoch
=> 0 );
is( exception {
$c
->insert_one( {
"date"
=>
$date
} ) },
undef
,
"inserting DateTime at epoch succeeds"
);
};
subtest
"half-conversion to int type"
=>
sub
{
$c
->drop;
my
$var
=
'zzz'
;
{
no
warnings
'numeric'
;
$var
=
int
(
$var
)
if
(
int
(
$var
) eq
$var
);
}
$c
->insert_one({
'key'
=>
$var
});
my
$v
=
$c
->find_one;
is(
$v
->{
'key'
},
'zzz'
);
};
subtest
"store a scalar with magic that's both a float and int (PVMG w/pIOK set)"
=>
sub
{
$c
->drop;
my
$size
= Person->new(
size
=> 11.5 )->size;
{
no
warnings
'void'
;
int
(
$size
);
}
$c
->insert_one({
'key'
=>
$size
});
my
$v
=
$c
->find_one;
is((
$v
->{
'key'
}),
$size
);
};
subtest
"make sure _ids aren't double freed"
=>
sub
{
$c
->drop;
my
$insert1
= [
'_id'
=> 1];
my
$insert2
= Tie::IxHash->new(
'_id'
=> 2);
my
$id
=
$c
->insert_one(
$insert1
)->inserted_id;
is(
$id
, 1);
$id
=
$c
->insert_one(
$insert2
)->inserted_id;
is(
$id
, 2);
};
subtest
"aggressively convert numbers"
=>
sub
{
local
$MongoDB::BSON::looks_like_number
= 1;
my
$alt_client
= build_client();
my
$alt_c
=
$alt_client
->db(
$testdb
->name)->coll(
$c
->name);
$alt_c
->drop;
$alt_c
->insert_one({
num
=>
"4"
});
$alt_c
->insert_one({
num
=>
"5"
});
$alt_c
->insert_one({
num
=>
"6"
});
$alt_c
->insert_one({
num
=> 4});
$alt_c
->insert_one({
num
=> 5});
$alt_c
->insert_one({
num
=> 6});
is(
$alt_c
->count({
num
=> {
'$gt'
=> 4}}), 4);
is(
$alt_c
->count({
num
=> {
'$gte'
=>
"5"
}}), 4);
is(
$alt_c
->count({
num
=> {
'$gte'
=>
"4.1"
}}), 4);
};
subtest
"MongoDB::BSON::String type"
=>
sub
{
{
local
$MongoDB::BSON::looks_like_number
= 1;
my
$alt_client
= build_client();
my
$alt_c
=
$alt_client
->db(
$testdb
->name)->coll(
$c
->name);
$c
->drop;
my
$num
=
"001"
;
$alt_c
->insert_one({
num
=>
$num
} );
$alt_c
->insert_one({
num
=>
bless
(\
$num
,
"MongoDB::BSON::String"
)});
}
is(
$c
->count({
num
=> 1}), 1);
is(
$c
->count({
num
=>
"001"
}), 1);
is(
$c
->count, 2);
};
subtest
"MongoDB::BSON::Binary type"
=>
sub
{
$c
->drop;
my
$str
=
"foo"
;
my
$bin
= {
bindata
=> [
\
$str
,
MongoDB::BSON::Binary->new(
data
=>
$str
),
MongoDB::BSON::Binary->new(
data
=>
$str
,
subtype
=> MongoDB::BSON::Binary->SUBTYPE_GENERIC),
MongoDB::BSON::Binary->new(
data
=>
$str
,
subtype
=> MongoDB::BSON::Binary->SUBTYPE_FUNCTION),
MongoDB::BSON::Binary->new(
data
=>
$str
,
subtype
=> MongoDB::BSON::Binary->SUBTYPE_GENERIC_DEPRECATED),
MongoDB::BSON::Binary->new(
data
=>
$str
,
subtype
=> MongoDB::BSON::Binary->SUBTYPE_UUID_DEPRECATED),
MongoDB::BSON::Binary->new(
data
=>
$str
,
subtype
=> MongoDB::BSON::Binary->SUBTYPE_UUID),
MongoDB::BSON::Binary->new(
data
=>
$str
,
subtype
=> MongoDB::BSON::Binary->SUBTYPE_MD5),
MongoDB::BSON::Binary->new(
data
=>
$str
,
subtype
=> MongoDB::BSON::Binary->SUBTYPE_USER_DEFINED)]};
$c
->insert_one(
$bin
);
my
$doc
=
$c
->find_one;
my
$data
=
$doc
->{
'bindata'
};
foreach
(
@$data
) {
is(
$_
,
"foo"
);
}
$doc
=
$c
->find_one;
$data
=
$doc
->{
'bindata'
};
my
@arr
=
@$data
;
is(
$arr
[0]->subtype, MongoDB::BSON::Binary->SUBTYPE_GENERIC);
is(
$arr
[0]->data,
$str
);
for
(
my
$i
=1;
$i
<=
$#arr
;
$i
++ ) {
is(
$arr
[
$i
]->subtype,
$bin
->{
'bindata'
}->[
$i
]->subtype);
is(
$arr
[
$i
]->data,
$bin
->{
'bindata'
}->[
$i
]->data);
}
};
subtest
"Checking hash key unicode support"
=>
sub
{
$c
->drop;
my
$testkey
=
'юникод'
;
my
$hash
= {
$testkey
=> 1 };
my
$oid
;
eval
{
$oid
=
$c
->insert_one(
$hash
)->inserted_id; };
is ( $@,
''
);
my
$obj
=
$c
->find_one( {
_id
=>
$oid
} );
is (
$obj
->{
$testkey
}, 1 );
};
subtest
"PERL-489 ref to PVNV"
=>
sub
{
my
$value
= 42.2;
$value
=
"hello"
;
is(
exception {
$c
->insert_one( {
value
=> \
$value
} ) },
undef
,
"inserting ref to PVNV is not fatal"
,
);
};
done_testing;