#!/usr/bin/perl
#
# Test suite for krb5-strength-wordlist filtering functions.
#
# Written by Russ Allbery <eagle@eyrie.org>
# Copyright 2016, 2020 Russ Allbery <eagle@eyrie.org>
# Copyright 2014
#     The Board of Trustees of the Leland Stanford Junior University
#
# SPDX-License-Identifier: MIT

use 5.006;
use strict;
use warnings;

use lib "$ENV{SOURCE}/tap/perl";

use Test::RRA qw(use_prereq);
use Test::RRA::Automake qw(automake_setup test_file_path test_tmpdir);

use Encode qw(encode);
use Test::More;

# Load prerequisite modules.
use_prereq('IPC::Run',     'run');
use_prereq('Perl6::Slurp', 'slurp');

# Set up for testing of an Automake project.
automake_setup();

# Declare the plan.
plan tests => 5;

# Run krb5-strength-wordlist with the given arguments and verify that it exits
# successfully with no output.  For planning purposes, this function will
# report three tests.
#
# @args - Arguments to krb5-strength-wordlist
#
# Returns: undef
sub run_wordlist {
    my (@args) = @_;

    # Find the krb5-strength-wordlist program in the distribution.
    my $wordlist = test_file_path('../tools/krb5-strength-wordlist');

    # Run the program, capturing its output and status.
    my ($out, $err);
    run([$wordlist, @args], \undef, \$out, \$err);
    my $status = ($? >> 8);

    # Check the results.
    is($status, 0,   "krb5-strength-wordlist @args");
    is($out,    q{}, '...with no output');
    is($err,    q{}, '...and no errors');
    return;
}

# Read the word list that we'll use for testing.
my @wordlist = slurp(test_file_path('data/wordlist'));

# Generate a filtered version that should match the eventual output of
# krb5-strength-wordlist, removing words containing the letter d and any
# shorter than 8 characters.
my @filtered = grep { !m{d}xms && length >= 8 } @wordlist;

# Add a non-ASCII word to test non-ASCII filtering.
push(@wordlist, encode('UTF-8', "\N{U+0639}\N{U+0631}\N{U+0628}\N{U+649}"));

# Write the new wordlist, including the non-ASCII word, to a new file.
my $tmpdir = test_tmpdir();
open(my $wordlist_fh, q{>}, "$tmpdir/wordlist")
  or BAIL_OUT("cannot create to $tmpdir/wordlist: $!");
print {$wordlist_fh} join("\n", @wordlist), "\n"
  or BAIL_OUT("cannot write to $tmpdir/wordlist: $!");
close($wordlist_fh)
  or BAIL_OUT("cannot flush $tmpdir/wordlist: $!");

# Generate a new, filtered word list.  Remove non-ASCII, words containing the
# letter d, and words shorter than eight characters.
my @options = qw(-a -x .*d -l 8);
run_wordlist(@options, '-o', "$tmpdir/wordlist.new", "$tmpdir/wordlist");

# Verify that the new filtered list exists and has the correct content.
my @got = eval { slurp("$tmpdir/wordlist.new") };
is($@, q{}, 'New word list exists');
is_deeply(\@got, \@filtered, '...with correct contents');

# Remove the files created by the test.
unlink("$tmpdir/wordlist", "$tmpdir/wordlist.new");
