# SPDX-License-Identifier: GPL-2.0-or-later

package Amavis::UtilTest;

use Test::Most;
use base 'Test::Class';
use utf8;

use Encode;
use List::Util;
use YAML::XS;

sub class { 'Amavis::Util' }

sub startup : Tests(startup => 1) {
  my $test = shift;
  return 'Incomplete module';
  use_ok $test->class;
}

sub idn : Tests(5) {
  use_ok shift->class;

  my $domain = 'ö.example';
  utf8::encode($domain);

  my $ascii = Amavis::Util::idn_to_ascii($domain);
  is($ascii, 'xn--nda.example', 'idn_to_ascii');

  my $utf8 = Amavis::Util::idn_to_utf8($ascii);
  is($utf8, $domain, 'idn_to_utf8');

  my $address = 'local@ö.example';
  utf8::encode($address);

  $ascii = Amavis::Util::mail_addr_idn_to_ascii($address);
  is($ascii, 'local@xn--nda.example', 'mail_addr_idn_to_ascii');

  $utf8 = Amavis::Util::mail_addr_decode($ascii, 1);
  is($utf8, $address, 'mail_addr_decode');
}

sub q_encode : Tests {
  use_ok shift->class;

  my $data = join '', <DATA>;
  utf8::encode($data);
  my $testdata = Load($data);

  my $normalize = sub {
    my $in = shift;
    $in =~ s/^\s+//g;
    $in =~ s/\s+/ /g;
    $in = join ' ', map {
       s/^=[?]([^?]+)[?]q[?]/=?$1?Q?/r;
    } split ' ', $in;
    return $in;
  };

  # A multi-octet character may not be split across adjacent 'encoded-word's

  while (my ($encoding, $testdata) = each %$testdata) {
    subtest $encoding => sub {
      while (my ($input, $expected) = each %$testdata) {
        $input = Encode::encode($encoding, $input);
        my $output = Amavis::Util::q_encode($input, 'Q', $encoding);
        is $normalize->($output), $normalize->($expected);
      }
    }
  }
}

1;

__DATA__
# from email.charset import Charset, QP
# from email.header import Header
# from itertools import chain
# from yaml import dump
#
# def main():
#     data = dict()
#     setup = [
#         ('eucgb2312_cn', '鹿', range(49, 53)),
#         ('utf-16be', 'ö', range(12, 16)),
#         ('utf-16le', 'ö', range(12, 16)),
#         ('utf-8', 'ö', range(56, 60)),
#     ]
#     for charset, char, rng in setup:
#         cset = Charset(charset)
#         cset.header_encoding = QP
#         data.setdefault(charset, {})[''] = Header('', charset=cset, maxlinelen=75).encode()
#         for len in chain((0, 1), rng):
#             input = f'{"Z" * len}{char}'
#             data.setdefault(charset, {})[input] = Header(input, charset=cset, maxlinelen=75).encode()
#     with open(__file__) as f:
#         for line in f.readlines():
#             print(f'# {line}', end='')
#     print()
#     print(dump(data, default_style='|'))
#
# if __name__ == '__main__':
#     main()

"eucgb2312_cn":
  ? ""
  : ""
  "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ\u9E7F": |-
    =?eucgb2312_cn?q?ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ?=
     =?eucgb2312_cn?q?=C2=B9?=
  "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ\u9E7F": |-
    =?eucgb2312_cn?q?ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ?=
     =?eucgb2312_cn?q?=C2=B9?=
  "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ\u9E7F": |-
    =?eucgb2312_cn?q?ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ=C2=B9?=
  "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ\u9E7F": |-
    =?eucgb2312_cn?q?ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ=C2=B9?=
  "Z\u9E7F": |-
    =?eucgb2312_cn?q?Z=C2=B9?=
  "\u9E7F": |-
    =?eucgb2312_cn?q?=C2=B9?=
"utf-16be":
  ? ""
  : ""
  "ZZZZZZZZZZZZZZZ\xF6": |-
    =?utf-16be?q?=00Z=00Z=00Z=00Z=00Z=00Z=00Z=00Z=00Z=00Z=00Z=00Z=00Z=00Z=00Z?=
     =?utf-16be?q?=00=F6?=
  "ZZZZZZZZZZZZZZ\xF6": |-
    =?utf-16be?q?=00Z=00Z=00Z=00Z=00Z=00Z=00Z=00Z=00Z=00Z=00Z=00Z=00Z=00Z?=
     =?utf-16be?q?=00=F6?=
  "ZZZZZZZZZZZZZ\xF6": |-
    =?utf-16be?q?=00Z=00Z=00Z=00Z=00Z=00Z=00Z=00Z=00Z=00Z=00Z=00Z=00Z=00=F6?=
  "ZZZZZZZZZZZZ\xF6": |-
    =?utf-16be?q?=00Z=00Z=00Z=00Z=00Z=00Z=00Z=00Z=00Z=00Z=00Z=00Z=00=F6?=
  "Z\xF6": |-
    =?utf-16be?q?=00Z=00=F6?=
  "\xF6": |-
    =?utf-16be?q?=00=F6?=
"utf-16le":
  ? ""
  : ""
  "ZZZZZZZZZZZZZZZ\xF6": |-
    =?utf-16le?q?Z=00Z=00Z=00Z=00Z=00Z=00Z=00Z=00Z=00Z=00Z=00Z=00Z=00Z=00Z=00?=
     =?utf-16le?q?=F6=00?=
  "ZZZZZZZZZZZZZZ\xF6": |-
    =?utf-16le?q?Z=00Z=00Z=00Z=00Z=00Z=00Z=00Z=00Z=00Z=00Z=00Z=00Z=00Z=00?=
     =?utf-16le?q?=F6=00?=
  "ZZZZZZZZZZZZZ\xF6": |-
    =?utf-16le?q?Z=00Z=00Z=00Z=00Z=00Z=00Z=00Z=00Z=00Z=00Z=00Z=00Z=00=F6=00?=
  "ZZZZZZZZZZZZ\xF6": |-
    =?utf-16le?q?Z=00Z=00Z=00Z=00Z=00Z=00Z=00Z=00Z=00Z=00Z=00Z=00=F6=00?=
  "Z\xF6": |-
    =?utf-16le?q?Z=00=F6=00?=
  "\xF6": |-
    =?utf-16le?q?=F6=00?=
"utf-8":
  ? ""
  : ""
  "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ\xF6": |-
    =?utf-8?q?ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ?=
     =?utf-8?q?=C3=B6?=
  "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ\xF6": |-
    =?utf-8?q?ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ?=
     =?utf-8?q?=C3=B6?=
  "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ\xF6": |-
    =?utf-8?q?ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ=C3=B6?=
  "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ\xF6": |-
    =?utf-8?q?ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ=C3=B6?=
  "Z\xF6": |-
    =?utf-8?q?Z=C3=B6?=
  "\xF6": |-
    =?utf-8?q?=C3=B6?=
