--- /dev/null
+#!/usr/bin/env perl
+
+use warnings;
+use strict;
+
+use lib 't/lib';
+use TestCommon;
+
+use Test::More;
+
+BEGIN { use_ok 'File::KDBX::Key::YubiKey' }
+
+local $ENV{YKCHALRESP} = testfile(qw{bin ykchalresp});
+local $ENV{YKINFO} = testfile(qw{bin ykinfo});
+
+{
+ my ($pre, $post);
+ my $key = File::KDBX::Key::YubiKey->new(
+ pre_challenge => sub { ++$pre },
+ post_challenge => sub { ++$post },
+ );
+ my $resp;
+ is exception { $resp = $key->challenge('foo') }, undef,
+ 'Do not throw during non-blocking response';
+ is $resp, "\xf0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 'Get a non-blocking challenge response';
+ is length($resp), 20, 'Response is the proper length';
+ is $pre, 1, 'The pre-challenge callback is called';
+ is $post, 1, 'The post-challenge callback is called';
+}
+
+{
+ my $key = File::KDBX::Key::YubiKey->new;
+ local $ENV{YKCHALRESP_MOCK} = 'error';
+ like exception { $key->challenge('foo') }, qr/Yubikey core error:/i,
+ 'Throw if challenge-response program errored out';
+}
+
+{
+ my $key = File::KDBX::Key::YubiKey->new;
+ local $ENV{YKCHALRESP_MOCK} = 'usberror';
+ like exception { $key->challenge('foo') }, qr/USB error:/i,
+ 'Throw if challenge-response program had a USB error';
+}
+
+{
+ my $key = File::KDBX::Key::YubiKey->new(timeout => 0, device => 3, slot => 2);
+ local $ENV{YKCHALRESP_MOCK} = 'block';
+
+ like exception { $key->challenge('foo') }, qr/operation would block/i,
+ 'Throw if challenge would block but we do not want to wait';
+
+ $key->timeout(1);
+ like exception { $key->challenge('foo') }, qr/timed out/i,
+ 'Timed out while waiting for response';
+
+ $key->timeout(-1);
+ my $resp;
+ is exception { $resp = $key->challenge('foo') }, undef,
+ 'Do not throw during blocking response';
+ is $resp, "\xf0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 'Get a blocking challenge response';
+}
+
+{
+ my $key = File::KDBX::Key::YubiKey->new(device => 0, slot => 1);
+ is $key->name, 'YubiKey NEO FIDO v2.0.0 [123] (slot #1)',
+ 'Get name for a new, unscanned key';
+ is $key->serial, 123, 'We have the serial number of the new key';
+}
+
+{
+ my ($key, @other) = File::KDBX::Key::YubiKey->scan;
+ is $key->name, 'YubiKey 4/5 OTP v3.0.1 [456] (slot #2)',
+ 'Find expected YubiKey';
+ is $key->serial, 456, 'We have the serial number of the scanned key';
+ is scalar @other, 0, 'Do not find any other YubiKeys';
+}
+
+{
+ local $ENV{YKCHALRESP} = testfile(qw{bin nonexistent});
+ my $key = File::KDBX::Key::YubiKey->new;
+ like exception { $key->challenge('foo') }, qr/failed to run|failed to receive challenge response/i,
+ 'Throw if the program failed to run';
+}
+
+done_testing;