use Mojo::Base -strict;

use Test::More;
use Mojo::JSON::Pointer;

subtest '"contains" (hash)' => sub {
  my $pointer = Mojo::JSON::Pointer->new({foo => 23, '' => 24});
  ok $pointer->contains(''),                                       'contains ""';
  ok $pointer->contains('/'),                                      'contains "/"';
  ok $pointer->contains('/foo'),                                   'contains "/foo"';
  ok !$pointer->contains('foo'),                                   '"foo" is invalid';
  ok !$pointer->contains('/bar'),                                  'does not contains "/bar"';
  ok $pointer->new({foo => {bar => undef}})->contains('/foo/bar'), 'contains "/foo/bar"';
};

subtest '"contains" (string)' => sub {
  my $pointer = Mojo::JSON::Pointer->new('works');
  ok $pointer->contains(''),           'contains ""';
  ok !$pointer->contains('/'),         'does not contain "/"';
  ok !$pointer->contains('/foo'),      'does not contain "/foo"';
  ok $pointer->new('0')->contains(''), 'contains ""';
};

subtest '"contains" (mixed)' => sub {
  my $pointer = Mojo::JSON::Pointer->new({foo => [0, 1, 2]});
  ok $pointer->contains(''),          'contains ""';
  ok $pointer->contains('/foo/0'),    'contains "/foo/0"';
  ok !$pointer->contains('/foo/9'),   'does not contain "/foo/9"';
  ok !$pointer->contains('/foo/bar'), 'does not contain "/foo/bar"';
  ok !$pointer->contains('/0'),       'does not contain "/0"';
  ok !$pointer->contains('/'),        'does not contain "/"';
};

subtest '"get" (hash)' => sub {
  my $pointer = Mojo::JSON::Pointer->new({foo => 'bar', '' => 'baz'});
  is_deeply $pointer->get(''), {foo => 'bar', '' => 'baz'}, '"" is "{foo => "bar", "" => "baz"}"';
  is $pointer->get('/'),                                   'baz', '"/" is "baz"';
  is $pointer->get('/foo'),                                'bar', '"/foo" is "bar"';
  is $pointer->get('foo'),                                 undef, '"foo" is invalid';
  is $pointer->new({foo => {bar => 42}})->get('/foo/bar'), 42,    '"/foo/bar" is "42"';
  is_deeply $pointer->new({foo => {23 => {baz => 0}}})->get('/foo/23'), {baz => 0}, '"/foo/23" is "{baz => 0}"';
  is $pointer->new({foo => {'' => 42}})->get('/foo/'),          42, '"/foo/" is "42"';
  is $pointer->new({foo => {'' => {'' => 42}}})->get('/foo//'), 42, '"/foo//" is "42"';
};

subtest '"get" (string)' => sub {
  my $pointer = Mojo::JSON::Pointer->new('works');
  is $pointer->get(''),           'works', '"" is "works"';
  is $pointer->get('/'),          undef,   '"/" is undef';
  is $pointer->get('/foo'),       undef,   '"/foo" is undef';
  is $pointer->new('0')->get(''), 0,       '"/foo" is "0"';
};

subtest '"get" (mixed)' => sub {
  my $pointer = Mojo::JSON::Pointer->new;
  is_deeply $pointer->new({foo => {bar => [1, 2, 3]}})->get('/foo/bar'), [1, 2, 3], '"/foo/bar" is "[1, 2, 3]"';
  $pointer = Mojo::JSON::Pointer->new({foo => {bar => [0, undef, 3]}});
  is $pointer->get('/foo/bar/0'), 0,     '"/foo/bar/0" is "0"';
  is $pointer->get('/foo/bar/1'), undef, '"/foo/bar/1" is undef';
  is $pointer->get('/foo/bar/2'), 3,     '"/foo/bar/2" is "3"';
  is $pointer->get('/foo/bar/6'), undef, '"/foo/bar/6" is undef';
};

subtest '"get" (encoded)' => sub {
  my $pointer = Mojo::JSON::Pointer->new;
  is $pointer->new([{'foo/bar'     => 'bar'}])->get('/0/foo~1bar'),       'bar',  '"/0/foo~1bar" is "bar"';
  is $pointer->new([{'foo/bar/baz' => 'yada'}])->get('/0/foo~1bar~1baz'), 'yada', '"/0/foo~1bar~1baz" is "yada"';
  is $pointer->new([{'foo~/bar'    => 'bar'}])->get('/0/foo~0~1bar'),     'bar',  '"/0/foo~0~1bar" is "bar"';
  is $pointer->new([{'f~o~o~/b~'   => {'a~' => {'r' => 'baz'}}}])->get('/0/f~0o~0o~0~1b~0/a~0/r'), 'baz',
    '"/0/f~0o~0o~0~1b~0/a~0/r" is "baz"';
  is $pointer->new({'~1' => 'foo'})->get('/~01'), 'foo', '"/~01" is "foo"';
};

subtest 'Unicode' => sub {
  my $pointer = Mojo::JSON::Pointer->new;
  is $pointer->new({'☃' => 'snowman'})->get('/☃'),           'snowman', 'found the snowman';
  is $pointer->new->data({'☃' => ['snowman']})->get('/☃/0'), 'snowman', 'found the snowman';
};

subtest 'RFC 6901' => sub {
  my $hash = {
    foo    => ['bar', 'baz'],
    ''     => 0,
    'a/b'  => 1,
    'c%d'  => 2,
    'e^f'  => 3,
    'g|h'  => 4,
    'i\\j' => 5,
    'k"l'  => 6,
    ' '    => 7,
    'm~n'  => 8
  };
  my $pointer = Mojo::JSON::Pointer->new($hash);
  is_deeply $pointer->get(''),     $hash,          'empty pointer is whole document';
  is_deeply $pointer->get('/foo'), ['bar', 'baz'], '"/foo" is "["bar", "baz"]"';
  is $pointer->get('/foo/0'), 'bar', '"/foo/0" is "bar"';
  is $pointer->get('/'),      0,     '"/" is 0';
  is $pointer->get('/a~1b'),  1,     '"/a~1b" is 1';
  is $pointer->get('/c%d'),   2,     '"/c%d" is 2';
  is $pointer->get('/e^f'),   3,     '"/e^f" is 3';
  is $pointer->get('/g|h'),   4,     '"/g|h" is 4';
  is $pointer->get('/i\\j'),  5,     '"/i\\\\j" is 5';
  is $pointer->get('/k"l'),   6,     '"/k\\"l" is 6';
  is $pointer->get('/ '),     7,     '"/ " is 7';
  is $pointer->get('/m~0n'),  8,     '"/m~0n" is 8';
};

done_testing();
