/*
 * Copyright (c) 2009, 2023 Oracle and/or its affiliates. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0, which is available at
 * http://www.eclipse.org/legal/epl-2.0.
 *
 * This Source Code may also be made available under the following Secondary
 * Licenses when the conditions for such availability set forth in the
 * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
 * version 2 with the GNU Classpath Exception, which is available at
 * https://www.gnu.org/software/classpath/license.html.
 *
 * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
 */

package org.xbib.net.mail.test.smtp;

import jakarta.mail.Session;
import jakarta.mail.Transport;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Timeout;
import org.xbib.net.mail.test.test.TestServer;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.nio.charset.StandardCharsets;
import java.util.Properties;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;

/**
 * Test that authentication information is only included in
 * the debug output when explicitly requested by setting the
 * property "mail.debug.auth" to "true".
 *
 * XXX - should test all authentication types, but that requires
 * more work in the dummy test server.
 */
@Timeout(20)
public final class SMTPAuthDebugTest {

    /**
     * Test that authentication information isn't included in the debug output.
     */
    @Test
    public void testNoAuthDefault() {
        final Properties properties = new Properties();
        assertFalse(test(properties, "AUTH"));
    }

    @Test
    public void testNoAuth() {
        final Properties properties = new Properties();
        properties.setProperty("mail.debug.auth", "false");
        assertFalse(test(properties, "AUTH"));
    }

    /**
     * Test that authentication information *is* included in the debug output.
     */
    @Test
    public void testAuth() {
        final Properties properties = new Properties();
        properties.setProperty("mail.debug.auth", "true");
        assertTrue(test(properties, "AUTH"));
    }

    /**
     * Create a test server, connect to it, and collect the debug output.
     * Scan the debug output looking for "expect", return true if found.
     */
    public boolean test(Properties properties, String expect) {
        TestServer server = null;
        try {
            final SMTPHandler handler = new SMTPHandler();
            server = new TestServer(handler);
            server.start();
            Thread.sleep(1000);

            properties.setProperty("mail.smtp.host", "localhost");
            properties.setProperty("mail.smtp.port", String.valueOf(server.getPort()));
            final Session session = Session.getInstance(properties);
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            PrintStream ps = new PrintStream(bos);
            session.setDebugOut(ps);
            session.setDebug(true);

            final Transport t = session.getTransport("smtp");
            try {
                t.connect("test", "test");
            } catch (Exception ex) {
                System.out.println(ex);
                //ex.printStackTrace();
                fail(ex.toString());
            } finally {
                t.close();
            }

            ps.close();
            bos.close();
            ByteArrayInputStream bis =
                    new ByteArrayInputStream(bos.toByteArray());
            BufferedReader r = new BufferedReader(
                    new InputStreamReader(bis, StandardCharsets.US_ASCII));
            String line;
            boolean found = false;
            while ((line = r.readLine()) != null) {
                if (line.startsWith("DEBUG"))
                    continue;
                if (line.startsWith("*"))
                    continue;
                if (line.startsWith(expect))
                    found = true;
            }
            r.close();
            return found;
        } catch (final Exception e) {
            e.printStackTrace();
            fail(e.getMessage());
            return false;    // XXX - doesn't matter
        } finally {
            if (server != null) {
                server.quit();
            }
        }
    }
}
