/*
 * ====================================================================
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 *
 */
package org.apache.hc.client5.http.impl.auth;

import org.apache.hc.client5.http.auth.AuthScope;
import org.apache.hc.client5.http.auth.Credentials;
import org.apache.hc.client5.http.auth.CredentialsProvider;
import org.apache.hc.client5.http.auth.StandardAuthScheme;
import org.apache.hc.client5.http.auth.UsernamePasswordCredentials;
import org.apache.hc.core5.http.HttpHost;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

/**
 * Tests for {@link org.apache.hc.client5.http.auth.CredentialsProvider} implementations.
 */
class TestCredentialsProviders {

    public final static Credentials CREDS1 =
        new UsernamePasswordCredentials("user1", "pass1".toCharArray());
    public final static Credentials CREDS2 =
        new UsernamePasswordCredentials("user2", "pass2".toCharArray());

    public final static AuthScope SCOPE1 = new AuthScope(null, null, -1, "realm1", null);
    public final static AuthScope SCOPE2 = new AuthScope(null, null, -1, "realm2", null);
    public final static AuthScope BOGUS = new AuthScope(null, null, -1, "bogus", null);
    public final static AuthScope DEFSCOPE = new AuthScope(null, "host", -1, "realm", null);

    @Test
    void testBasicCredentialsProviderCredentials() {
        final BasicCredentialsProvider state = new BasicCredentialsProvider();
        state.setCredentials(SCOPE1, CREDS1);
        state.setCredentials(SCOPE2, CREDS2);
        Assertions.assertEquals(CREDS1, state.getCredentials(SCOPE1, null));
        Assertions.assertEquals(CREDS2, state.getCredentials(SCOPE2, null));
    }

    @Test
    void testBasicCredentialsProviderNoCredentials() {
        final BasicCredentialsProvider state = new BasicCredentialsProvider();
        Assertions.assertNull(state.getCredentials(BOGUS, null));
    }

    @Test
    void testBasicCredentialsProviderDefaultCredentials() {
        final BasicCredentialsProvider state = new BasicCredentialsProvider();
        state.setCredentials(new AuthScope(null, null, -1, null ,null), CREDS1);
        state.setCredentials(SCOPE2, CREDS2);
        Assertions.assertEquals(CREDS1, state.getCredentials(BOGUS, null));
    }

    @Test
    void testDefaultCredentials() {
        final BasicCredentialsProvider state = new BasicCredentialsProvider();
        final Credentials expected = new UsernamePasswordCredentials("name", "pass".toCharArray());
        state.setCredentials(new AuthScope(null, null, -1, null ,null), expected);
        final Credentials got = state.getCredentials(DEFSCOPE, null);
        Assertions.assertEquals(got, expected);
    }

    @Test
    void testRealmCredentials() {
        final BasicCredentialsProvider state = new BasicCredentialsProvider();
        final Credentials expected = new UsernamePasswordCredentials("name", "pass".toCharArray());
        state.setCredentials(DEFSCOPE, expected);
        final Credentials got = state.getCredentials(DEFSCOPE, null);
        Assertions.assertEquals(expected, got);
    }

    @Test
    void testHostCredentials() {
        final BasicCredentialsProvider state = new BasicCredentialsProvider();
        final Credentials expected = new UsernamePasswordCredentials("name", "pass".toCharArray());
        state.setCredentials(new AuthScope(null, "host", -1, null, null), expected);
        final Credentials got = state.getCredentials(DEFSCOPE, null);
        Assertions.assertEquals(expected, got);
    }

    @Test
    void testWrongHostCredentials() {
        final BasicCredentialsProvider state = new BasicCredentialsProvider();
        final Credentials expected = new UsernamePasswordCredentials("name", "pass".toCharArray());
        state.setCredentials(new AuthScope(null, "host1", -1, "realm", null), expected);
        final Credentials got = state.getCredentials(new AuthScope(null, "host2", -1, "realm", null), null);
        Assertions.assertNotSame(expected, got);
    }

    @Test
    void testWrongRealmCredentials() {
        final BasicCredentialsProvider state = new BasicCredentialsProvider();
        final Credentials cred = new UsernamePasswordCredentials("name", "pass".toCharArray());
        state.setCredentials(new AuthScope(null, "host", -1, "realm1", null), cred);
        final Credentials got = state.getCredentials(new AuthScope(null, "host", -1, "realm2", null), null);
        Assertions.assertNotSame(cred, got);
    }

    @Test
    void testMixedCaseHostname() {
        final HttpHost httpHost = new HttpHost("hOsT", 80);
        final BasicCredentialsProvider state = new BasicCredentialsProvider();
        final Credentials expected = new UsernamePasswordCredentials("name", "pass".toCharArray());
        state.setCredentials(new AuthScope(httpHost), expected);
        final Credentials got = state.getCredentials(DEFSCOPE, null);
        Assertions.assertEquals(expected, got);
    }

    @Test
    void testCredentialsMatching() {
        final Credentials creds1 = new UsernamePasswordCredentials("name1", "pass1".toCharArray());
        final Credentials creds2 = new UsernamePasswordCredentials("name2", "pass2".toCharArray());
        final Credentials creds3 = new UsernamePasswordCredentials("name3", "pass3".toCharArray());

        final AuthScope scope1 = new AuthScope(null, null, -1, null, null);
        final AuthScope scope2 = new AuthScope(null, null, -1, "somerealm", null);
        final AuthScope scope3 = new AuthScope(null, "somehost", -1, null, null);

        final BasicCredentialsProvider state = new BasicCredentialsProvider();
        state.setCredentials(scope1, creds1);
        state.setCredentials(scope2, creds2);
        state.setCredentials(scope3, creds3);

        Credentials got = state.getCredentials(new AuthScope("http", "someotherhost", 80, "someotherrealm", StandardAuthScheme.BASIC), null);
        Credentials expected = creds1;
        Assertions.assertEquals(expected, got);

        got = state.getCredentials(new AuthScope("http", "someotherhost", 80, "somerealm", StandardAuthScheme.BASIC), null);
        expected = creds2;
        Assertions.assertEquals(expected, got);

        got = state.getCredentials(new AuthScope("http", "somehost", 80, "someotherrealm", StandardAuthScheme.BASIC), null);
        expected = creds3;
        Assertions.assertEquals(expected, got);
    }

    @Test
    void testSingleCredentialsProvider() {
        final Credentials creds1 = new UsernamePasswordCredentials("name1", "pass1".toCharArray());
        final CredentialsProvider credentialsProvider1 = new SingleCredentialsProvider(new AuthScope(null, null, -1, null, null), creds1);

        Assertions.assertEquals(creds1, credentialsProvider1.getCredentials(new AuthScope(null, null, -1, null, null), null));
        Assertions.assertEquals(creds1, credentialsProvider1.getCredentials(new AuthScope("http", "someotherhost", 80, "somerealm", StandardAuthScheme.BASIC), null));

        final CredentialsProvider credentialsProvider2 = new SingleCredentialsProvider(new AuthScope(null, "somehost", 80, null, null), creds1);

        Assertions.assertEquals(creds1, credentialsProvider2.getCredentials(new AuthScope(null, null, -1, null, null), null));
        Assertions.assertEquals(creds1, credentialsProvider2.getCredentials(new AuthScope(null, "somehost", 80, null, null), null));
        Assertions.assertEquals(creds1, credentialsProvider2.getCredentials(new AuthScope("http", "somehost", 80, "somerealm", StandardAuthScheme.BASIC), null));
        Assertions.assertNull(credentialsProvider2.getCredentials(new AuthScope(null, "someotherhost", 80, null, null), null));
        Assertions.assertNull(credentialsProvider2.getCredentials(new AuthScope(null, "somehost", 8080, null, null), null));
    }

}
