/*
 * 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.
 */

package org.apache.commons.exec.environment;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;

import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.exec.OS;
import org.junit.Test;

/**
 */
public class EnvironmentUtilsTest {

    /**
     * Tests the behavior of the EnvironmentUtils.toStrings()
     * when using a {@code null} environment.
     */
    @Test
    public void testToStrings() {
        // check for a non-existing environment when passing null
        assertNull(EnvironmentUtils.toStrings(null));
        // check for an environment when filling in two variables
        final Map<String, String> env = new HashMap<>();
        assertArrayEquals(new String[0], EnvironmentUtils.toStrings(env));
        env.put("foo2", "bar2");
        env.put("foo", "bar");
        final String[] envStrings = EnvironmentUtils.toStrings(env);
        final String[] expected = {"foo2=bar2", "foo=bar"};
        // ensure the result does not depend on the hash ordering
        Arrays.sort(expected);
        Arrays.sort(envStrings);
        assertArrayEquals(expected, envStrings);
    }

    /**
     * Test to access the environment variables of the current
     * process. Please note that this test does not run on
     * java-gjc.
     *
     * @throws IOException the test failed
     */
    @Test
    public void testGetProcEnvironment() throws IOException {
        final Map<String, String> procEnvironment = EnvironmentUtils.getProcEnvironment();
        // we assume that there is at least one environment variable
        // for this process, i.e. $JAVA_HOME
        assertFalse("Expecting non-zero environment size", procEnvironment.isEmpty());
        final String[] envArgs = EnvironmentUtils.toStrings(procEnvironment);
        for (int i = 0; i < envArgs.length; i++) {
            assertNotNull("Entry " + i + " should not be null", envArgs[i]);
            assertFalse("Entry " + i + " should not be empty", envArgs[i].isEmpty());
            // System.out.println(envArgs[i]);
        }
    }

    /**
     * On Windows platforms test that accessing environment variables
     * can be done in a case-insensitive way, e.g. "PATH", "Path" and
     * "path" would reference the same environment variable.
     *
     * @throws IOException the test failed
     */
    @Test
    public void testGetProcEnvironmentCaseInsensitiveLookup() throws IOException {
        // run tests only on windows platforms
        if (!OS.isFamilyWindows()) {
            return;
        }

        // ensure that we have the same value for upper and lowercase keys
        final Map<String, String> procEnvironment = EnvironmentUtils.getProcEnvironment();
        for (final Entry<String, String> entry : procEnvironment.entrySet()) {
            final String key = entry.getKey();
            final String value = entry.getValue();
            assertEquals(value, procEnvironment.get(key.toLowerCase(Locale.ENGLISH)));
            assertEquals(value, procEnvironment.get(key.toUpperCase(Locale.ENGLISH)));
        }

        // add an environment variable and check access
        EnvironmentUtils.addVariableToEnvironment(procEnvironment, "foo=bar");
        assertEquals("bar", procEnvironment.get("FOO"));
        assertEquals("bar", procEnvironment.get("Foo"));
        assertEquals("bar", procEnvironment.get("foo"));
    }

    /**
     * Accessing environment variables is case-sensitive or not depending
     * on the operating system but the values of the environment variable
     * are always case-sensitive. So make sure that this assumption holds
     * on all operating systems.
     *
     * @throws Exception the test failed
     */
    @Test
    public void testCaseInsensitiveVariableLookup() throws Exception {
        final Map<String, String> procEnvironment = EnvironmentUtils.getProcEnvironment();
        // Check that case is preserved for values
        EnvironmentUtils.addVariableToEnvironment(procEnvironment, "foo=bAr");
        assertEquals("bAr", procEnvironment.get("foo"));
    }

    /**
     * Tests the behavior of the EnvironmentUtils.toStrings()
     * when using a {@code null} key given to the map.
     */
    @Test
    public void testToStringWithNullKey() {
        final Map<String, String> env = new HashMap<>();
        env.put(null, "TheNullKey");
        final String[] strings = EnvironmentUtils.toStrings(env);
        assertEquals(1, strings.length);
        assertEquals("=TheNullKey", strings[0]);
    }

    /**
     * Tests the behavior of the EnvironmentUtils.toStrings()
     * when using a {@code null} value given to the map.
     */
    @Test
    public void testToStringWithNullValue() {
        final Map<String, String> env = new HashMap<>();
        env.put("key", null);
        final String[] strings = EnvironmentUtils.toStrings(env);
        assertEquals(1, strings.length);
        assertEquals("key=", strings[0]);
    }

}
