package org.codehaus.plexus.interpolation;

/*
 * The MIT License
 *
 * Copyright (c) 2004, The Codehaus
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
 * of the Software, and to permit persons to whom the Software is furnished to do
 * so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

import java.io.StringReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;

/**
 * InterpolatorFilterReaderTest, heavily based on InterpolationFilterReaderTest. Heh, even the test strings remained the
 * same!
 *
 * @author cstamas
 *
 */
public class InterpolatorFilterReaderTest {
    /*
     * Added and commented by jdcasey@03-Feb-2005 because it is a bug in the InterpolationFilterReader.
     * kenneyw@15-04-2005 fixed the bug.
     */
    @Test
    public void testShouldNotInterpolateExpressionAtEndOfDataWithInvalidEndToken() throws Exception {
        Map m = new HashMap();
        m.put("test", "TestValue");

        String testStr = "This is a ${test";

        assertEquals("This is a ${test", interpolate(testStr, m));
    }

    /*
     * kenneyw@14-04-2005 Added test to check above fix.
     */
    @Test
    public void testShouldNotInterpolateExpressionWithMissingEndToken() throws Exception {
        Map m = new HashMap();
        m.put("test", "TestValue");

        String testStr = "This is a ${test, really";

        assertEquals("This is a ${test, really", interpolate(testStr, m));
    }

    @Test
    public void testShouldNotInterpolateWithMalformedStartToken() throws Exception {
        Map m = new HashMap();
        m.put("test", "testValue");

        String foo = "This is a $!test} again";

        assertEquals("This is a $!test} again", interpolate(foo, m));
    }

    @Test
    public void testShouldNotInterpolateWithMalformedEndToken() throws Exception {
        Map m = new HashMap();
        m.put("test", "testValue");

        String foo = "This is a ${test!} again";

        assertEquals("This is a ${test!} again", interpolate(foo, m));
    }

    @Test
    public void testDefaultInterpolationWithNonInterpolatedValueAtEnd() throws Exception {
        Map m = new HashMap();
        m.put("name", "jason");
        m.put("noun", "asshole");

        String foo = "${name} is an ${noun}. ${not.interpolated}";

        assertEquals("jason is an asshole. ${not.interpolated}", interpolate(foo, m));
    }

    @Test
    public void testDefaultInterpolationWithInterpolatedValueAtEnd() throws Exception {
        Map m = new HashMap();
        m.put("name", "jason");
        m.put("noun", "asshole");

        String foo = "${name} is an ${noun}";

        assertEquals("jason is an asshole", interpolate(foo, m));
    }

    @Test
    public void testInterpolationWithInterpolatedValueAtEndWithCustomToken() throws Exception {
        Map m = new HashMap();
        m.put("name", "jason");
        m.put("noun", "asshole");

        String foo = "@{name} is an @{noun}";

        assertEquals("jason is an asshole", interpolate(foo, m, "@{", "}"));
    }

    @Test
    public void testInterpolationWithInterpolatedValueAtEndWithCustomTokenAndCustomString() throws Exception {
        Map m = new HashMap();
        m.put("name", "jason");
        m.put("noun", "asshole");

        String foo = "@name@ is an @noun@";

        assertEquals("jason is an asshole", interpolate(foo, m, "@", "@"));
    }

    @Test
    public void testEscape() throws Exception {
        Map m = new HashMap();
        m.put("name", "jason");
        m.put("noun", "asshole");

        String foo = "${name} is an \\${noun}";

        assertEquals("jason is an ${noun}", interpolate(foo, m, "\\"));
    }

    @Test
    public void testEscapeAtStart() throws Exception {
        Map m = new HashMap();
        m.put("name", "jason");
        m.put("noun", "asshole");

        String foo = "\\${name} is an \\${noun}";

        assertEquals("${name} is an ${noun}", interpolate(foo, m, "\\"));
    }

    @Test
    public void testEscapeOnlyAtStart() throws Exception {
        Map m = new HashMap();
        m.put("name", "jason");
        m.put("noun", "asshole");

        String foo = "\\@name@ is an @noun@";

        String result = interpolate(foo, m, "@", "@");
        assertEquals("@name@ is an asshole", result);
    }

    @Test
    public void testEscapeOnlyAtStartDefaultToken() throws Exception {
        Map m = new HashMap();
        m.put("name", "jason");
        m.put("noun", "asshole");

        String foo = "\\${name} is an ${noun}";

        String result = interpolate(foo, m, "${", "}");
        assertEquals("${name} is an asshole", result);
    }

    @Test
    public void testShouldDetectRecursiveExpressionPassingThroughTwoPrefixes() throws Exception {
        List prefixes = new ArrayList();

        prefixes.add("prefix1");
        prefixes.add("prefix2");

        RecursionInterceptor ri = new PrefixAwareRecursionInterceptor(prefixes, false);

        Map context = new HashMap();
        context.put("name", "${prefix2.name}");

        String input = "${prefix1.name}";

        StringSearchInterpolator interpolator = new StringSearchInterpolator();

        interpolator.addValueSource(new MapBasedValueSource(context));

        InterpolatorFilterReader r = new InterpolatorFilterReader(new StringReader(input), interpolator, ri);
        r.setInterpolateWithPrefixPattern(false);
        r.setEscapeString("\\");
        StringBuilder buf = new StringBuilder();
        int read = -1;
        char[] cbuf = new char[1024];
        while ((read = r.read(cbuf)) > -1) {
            buf.append(cbuf, 0, read);
        }

        assertEquals(input, buf.toString());
    }

    @Test
    public void testShouldDetectRecursiveExpressionWithPrefixAndWithout() throws Exception {
        List prefixes = new ArrayList();

        prefixes.add("prefix1");

        RecursionInterceptor ri = new PrefixAwareRecursionInterceptor(prefixes, false);

        Map context = new HashMap();
        context.put("name", "${prefix1.name}");

        String input = "${name}";

        StringSearchInterpolator interpolator = new StringSearchInterpolator();

        interpolator.addValueSource(new MapBasedValueSource(context));

        InterpolatorFilterReader r = new InterpolatorFilterReader(new StringReader(input), interpolator, ri);
        r.setInterpolateWithPrefixPattern(false);
        r.setEscapeString("\\");
        StringBuilder buf = new StringBuilder();
        int read = -1;
        char[] cbuf = new char[1024];
        while ((read = r.read(cbuf)) > -1) {
            buf.append(cbuf, 0, read);
        }

        assertEquals("${prefix1.name}", buf.toString());
    }

    // ----------------------------------------------------------------------
    //
    // ----------------------------------------------------------------------

    private String interpolate(String input, Map context) throws Exception {
        return interpolate(input, context, null);
    }

    private String interpolate(String input, Map context, String escapeStr) throws Exception {
        Interpolator interpolator = new StringSearchInterpolator();

        interpolator.addValueSource(new MapBasedValueSource(context));

        InterpolatorFilterReader r = new InterpolatorFilterReader(new StringReader(input), interpolator);
        r.setInterpolateWithPrefixPattern(false);
        if (escapeStr != null) {
            r.setEscapeString(escapeStr);
        }
        StringBuilder buf = new StringBuilder();
        int read = -1;
        char[] cbuf = new char[1024];
        while ((read = r.read(cbuf)) > -1) {
            buf.append(cbuf, 0, read);
        }

        return buf.toString();
    }

    private String interpolate(String input, Map context, String beginToken, String endToken) throws Exception {
        StringSearchInterpolator interpolator = new StringSearchInterpolator(beginToken, endToken);

        interpolator.addValueSource(new MapBasedValueSource(context));

        InterpolatorFilterReader r =
                new InterpolatorFilterReader(new StringReader(input), interpolator, beginToken, endToken);
        r.setInterpolateWithPrefixPattern(false);
        r.setEscapeString("\\");
        StringBuilder buf = new StringBuilder();
        int read = -1;
        char[] cbuf = new char[1024];
        while ((read = r.read(cbuf)) > -1) {
            buf.append(cbuf, 0, read);
        }

        return buf.toString();
    }
}
