/** * Copyright 2015 StreamSets Inc. * * Licensed under 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 com.streamsets.datacollector.el; import com.streamsets.pipeline.api.el.ELEvalException; import com.streamsets.pipeline.lib.el.StringEL; import org.junit.Assert; import org.junit.Test; import java.util.HashMap; import java.util.Map; import java.util.regex.Pattern; public class TestStringEL { @Test public void testSubstring() throws Exception { ELEvaluator eval = new ELEvaluator("testSubstring", StringEL.class); ELVariables variables = new ELVariables(); Assert.assertEquals("StreamSets", eval.eval(variables, "${str:substring(\"The StreamSets Inc\", 4, 14)}", String.class)); //End index greater than length, return beginIndex to end of string Assert.assertEquals("StreamSets Inc", eval.eval(variables, "${str:substring(\"The StreamSets Inc\", 4, 50)}", String.class)); //Begin Index > length, return "" Assert.assertEquals("", eval.eval(variables, "${str:substring(\"The StreamSets Inc\", 50, 60)}", String.class)); } @Test public void testSubstringNegative() throws Exception { ELEvaluator eval = new ELEvaluator("testSubstringNegative", StringEL.class); ELVariables variables = new ELVariables(); try { eval.eval(variables, "${str:substring(\"The StreamSets Inc\", -1, 14)}", String.class); Assert.fail("ELException expected as the begin index is negative"); } catch (ELEvalException e) { } try { eval.eval(variables, "${str:substring(\"The StreamSets Inc\", 0, -3)}", String.class); Assert.fail("ELException expected as the end index is negative"); } catch (ELEvalException e) { } //Input is empty, return empty Assert.assertEquals("", eval.eval(variables, "${str:substring(\"\", 0, 5)}", String.class)); } @Test public void testTrim() throws Exception { ELEvaluator eval = new ELEvaluator("testTrim", StringEL.class); ELVariables variables = new ELVariables(); Assert.assertEquals("StreamSets", eval.eval(variables, "${str:trim(\" StreamSets \")}", String.class)); } @Test public void testToUpper() throws Exception { ELEvaluator eval = new ELEvaluator("testToUpper", StringEL.class); ELVariables variables = new ELVariables(); Assert.assertEquals("STREAMSETS", eval.eval(variables, "${str:toUpper(\"StreamSets\")}", String.class)); } @Test public void testToLower() throws Exception { ELEvaluator eval = new ELEvaluator("testToLower", StringEL.class); ELVariables variables = new ELVariables(); Assert.assertEquals("streamsets inc", eval.eval(variables, "${str:toLower(\"StreamSets INC\")}", String.class)); } @Test public void testReplace() throws Exception { ELEvaluator eval = new ELEvaluator("testReplace", StringEL.class); ELVariables variables = new ELVariables(); Assert.assertEquals("The.Streamsets.Inc", eval.eval(variables, "${str:replace(\"The Streamsets Inc\", ' ', '.')}", String.class)); // SDC-5165 Assert.assertEquals("12345", eval.eval(variables, "${str:replace(\"_12345_\",\"_\",\"\")}", String.class)); } @Test public void testReplaceAll() throws Exception { ELEvaluator eval = new ELEvaluator("testReplaceAll", StringEL.class); ELVariables variables = new ELVariables(); Assert.assertEquals("The Streamsets Company", eval.eval(variables, "${str:replaceAll(\"The Streamsets Inc\", \"Inc\", \"Company\")}", String.class)); } @Test public void testContains() throws Exception { ELEvaluator eval = new ELEvaluator("testContains", StringEL.class); ELVariables variables = new ELVariables(); Assert.assertTrue(eval.eval(variables, "${str:contains(\"The Streamsets Inc\", \"Inc\")}", Boolean.class)); Assert.assertFalse(eval.eval(variables, "${str:contains(\"The Streamsets Inc\", \"Incorporated\")}", Boolean.class)); } @Test public void testStartsWith() throws Exception { ELEvaluator eval = new ELEvaluator("testStartsWith", StringEL.class); ELVariables variables = new ELVariables(); Assert.assertTrue(eval.eval(variables, "${str:startsWith(\"The Streamsets Inc\", \"The Streamsets\")}", Boolean.class)); Assert.assertFalse(eval.eval(variables, "${str:startsWith(\"The Streamsets Inc\", \"Streamsets Inc\")}", Boolean.class)); } @Test public void testEndsWith() throws Exception { ELEvaluator eval = new ELEvaluator("testEndsWith", StringEL.class); ELVariables variables = new ELVariables(); Assert.assertFalse(eval.eval(variables, "${str:endsWith(\"The Streamsets Inc\", \"The Streamsets\")}", Boolean.class)); Assert.assertTrue(eval.eval(variables, "${str:endsWith(\"The Streamsets Inc\", \"Streamsets Inc\")}", Boolean.class)); } @Test public void testTruncate() throws Exception { ELEvaluator eval = new ELEvaluator("testTruncate", StringEL.class); ELVariables variables = new ELVariables(); Assert.assertEquals("The StreamSets", eval.eval(variables, "${str:truncate(\"The StreamSets Inc\", 14)}", String.class)); Assert.assertEquals("abc", eval.eval(variables, "${str:truncate(\"abcd\", 3)}", String.class)); // endIndex is 0. it should return empty string Assert.assertEquals("", eval.eval(variables, "${str:truncate(\"abcd\", 0)}", String.class)); // if original string is empty, it should return empty Assert.assertEquals("", eval.eval(variables, "${str:truncate(\"\", 3)}", String.class)); // string is shorter than endIndex. It should return the original string without truncate Assert.assertEquals("abcd", eval.eval(variables, "${str:truncate(\"abcd\", 10)}", String.class)); Assert.assertEquals("", eval.eval(variables, "${str:truncate(null, 10)}", String.class)); Assert.assertEquals("", eval.eval(variables, "${str:truncate(\"\", 0)}", String.class)); try { eval.eval(variables, "${str:truncate(\"abcd\", -4)}", String.class); Assert.fail("Should throw ELEvalException for negative endIndex"); } catch (ELEvalException e) { //pass } } @Test public void testRegExCapture() throws Exception { ELEvaluator eval = new ELEvaluator("testRegExCapture", StringEL.class); ELVariables variables = new ELVariables(); String result = eval.eval(variables, "${str:regExCapture(\"2015-01-18 22:31:51,813 DEBUG ZkClient - Received event: WatchedEvent state:Disconnected\"," + " \"(\\\\d{4}-\\\\d{2}-\\\\d{2}) (\\\\d{2}:\\\\d{2}:\\\\d{2},\\\\d{3}) ([^ ]*) ([^ ]*) - (.*)$\", " + "1)}", String.class); Assert.assertEquals("2015-01-18", result); result = eval.eval(variables, "${str:regExCapture(\"2015-01-18 22:31:51,813 DEBUG ZkClient - Received event: WatchedEvent state:Disconnected\"," + " \"(\\\\d{4}-\\\\d{2}-\\\\d{2}) (\\\\d{2}:\\\\d{2}:\\\\d{2},\\\\d{3}) ([^ ]*) ([^ ]*) - (.*)$\", " + "2)}", String.class); Assert.assertEquals("22:31:51,813", result); result = eval.eval(variables, "${str:regExCapture(\"2015-01-18 22:31:51,813 DEBUG ZkClient - Received event: WatchedEvent state:Disconnected\"," + " \"(\\\\d{4}-\\\\d{2}-\\\\d{2}) (\\\\d{2}:\\\\d{2}:\\\\d{2},\\\\d{3}) ([^ ]*) ([^ ]*) - (.*)$\", " + "3)}", String.class); Assert.assertEquals("DEBUG", result); result = eval.eval(variables, "${str:regExCapture(\"2015-01-18 22:31:51,813 DEBUG ZkClient - Received event: WatchedEvent state:Disconnected\"," + " \"(\\\\d{4}-\\\\d{2}-\\\\d{2}) (\\\\d{2}:\\\\d{2}:\\\\d{2},\\\\d{3}) ([^ ]*) ([^ ]*) - (.*)$\", " + "0)}", String.class); Assert.assertEquals("2015-01-18 22:31:51,813 DEBUG ZkClient - Received event: WatchedEvent state:Disconnected", result); } @Test public void testRegexCaptureMemoization() throws Exception { ELEvaluator eval = new ELEvaluator("testRegExCaptureMemoization", StringEL.class); ELVariables variables = new ELVariables(); Map<String, Pattern> memoizedRegex = new HashMap<>(); variables.addContextVariable(StringEL.MEMOIZED, memoizedRegex); final String regex = ".*"; eval.eval(variables, "${str:regExCapture(\"abcdef\", \"" + regex + "\", 0)}", String.class); Assert.assertEquals(1, memoizedRegex.size()); Pattern compiledPattern = memoizedRegex.get(regex); eval.eval(variables, "${str:regExCapture(\"abcdef\", \"" + regex + "\", 0)}", String.class); // When executed again, make sure it still only has one pattern. Assert.assertEquals(1, memoizedRegex.size()); // Same regex instance (no new regex was compiled Assert.assertEquals(compiledPattern, memoizedRegex.get(regex)); // Regex pattern was the one expected Assert.assertEquals(Pattern.compile(".*").pattern(), memoizedRegex.get(regex).pattern()); } @Test public void testConcat() throws Exception { ELEvaluator eval = new ELEvaluator("testConcat", StringEL.class); ELVariables variables = new ELVariables(); String result = eval.eval(variables, "${str:concat(\"abc\", \"def\")}", String.class); Assert.assertEquals("abcdef", result); result = eval.eval(variables, "${str:concat(\"\", \"def\")}", String.class); Assert.assertEquals("def", result); result = eval.eval(variables, "${str:concat(\"abc\", \"\")}", String.class); Assert.assertEquals("abc", result); result = eval.eval(variables, "${str:concat(\"\", \"\")}", String.class); Assert.assertTrue(result.isEmpty()); } @Test public void testMatches() throws Exception { ELEvaluator eval = new ELEvaluator("testMatches", StringEL.class); ELVariables variables = new ELVariables(); Assert.assertTrue(eval.eval(variables, "${str:matches(\"abc\", \"[a-z]+\")}", Boolean.class)); Assert.assertTrue(eval.eval(variables, "${str:matches(\"abc123\", \"[a-z]+[0-9]+\")}", Boolean.class)); Assert.assertTrue(eval.eval(variables, "${str:matches(\"abc123\", \".*\")}", Boolean.class)); Assert.assertTrue(eval.eval(variables, "${str:matches(\" bc cd\", \"[a-z ]+\")}", Boolean.class)); Assert.assertTrue(eval.eval(variables, "${str:matches(\"vcpip-hdvrjkdfkjd\", \"^(vc[rkpm]ip-hdvr.*)\")}", Boolean.class)); Assert.assertFalse(eval.eval(variables, "${str:matches(\"Abc\", \"[a-z]+\")}", Boolean.class)); Assert.assertFalse(eval.eval(variables, "${str:matches(\"abc\n123\", \".*\")}", Boolean.class)); } @Test public void testStringLength() throws Exception { ELEvaluator eval = new ELEvaluator("testStringLength", StringEL.class); ELVariables variables = new ELVariables(); Assert.assertTrue(eval.eval(variables, "${str:length(\"abc\")}", Integer.class) == 3); Assert.assertTrue(eval.eval(variables, "${str:length(\"\")}", Integer.class) == 0); Assert.assertTrue(eval.eval(variables, "${str:length(str:concat(\"abc\",\"def\"))}", Integer.class) == 6); Assert.assertTrue(eval.eval(variables, "${str:length(str:trim(\" abc \"))}", Integer.class) == 3); Assert.assertTrue(eval.eval(variables, "${str:length(str:substring(\"abcdef\", 0, 3))}", Integer.class) == 3); } @Test public void testUrlEncode() throws Exception { ELEvaluator eval = new ELEvaluator("testUrlEncode", StringEL.class); ELVariables variables = new ELVariables(); Assert.assertEquals("", eval.eval(variables, "${str:urlEncode(\"\", \"UTF8\")}", String.class)); Assert.assertEquals("Ahoj+tady+medusa", eval.eval(variables, "${str:urlEncode(\"Ahoj tady medusa\", \"UTF8\")}", String.class)); } @Test public void testUrlDecode() throws Exception { ELEvaluator eval = new ELEvaluator("testUrlDecode", StringEL.class); ELVariables variables = new ELVariables(); Assert.assertEquals("", eval.eval(variables, "${str:urlDecode(\"\", \"UTF8\")}", String.class)); Assert.assertEquals("Ahoj tady medusa", eval.eval(variables, "${str:urlDecode(\"Ahoj+tady+medusa\", \"UTF8\")}", String.class)); } @Test public void testEscapeXml10() throws Exception { ELEvaluator eval = new ELEvaluator("testXmlEscape10", StringEL.class); ELVariables variables = new ELVariables(); Assert.assertEquals("", eval.eval(variables, "${str:escapeXML10(\"\")}", String.class)); Assert.assertEquals( "< abc & def > ", // the 0001 control char is removed because not compatible with XML 1.0 eval.eval(variables, "${str:escapeXML10(\"< abc & def > \u0001\")}", String.class) ); } @Test public void testEscapeXml11() throws Exception { ELEvaluator eval = new ELEvaluator("testXmlEscape10", StringEL.class); ELVariables variables = new ELVariables(); Assert.assertEquals("", eval.eval(variables, "${str:escapeXML11(\"\")}", String.class)); Assert.assertEquals( "< abc & def > ", eval.eval(variables, "${str:escapeXML11(\"< abc & def > \u0001\")}", String.class) ); } @Test public void testUnescapeXml() throws Exception { ELEvaluator eval = new ELEvaluator("testXmlEscape10", StringEL.class); ELVariables variables = new ELVariables(); Assert.assertEquals("", eval.eval(variables, "${str:unescapeXML(\"\")}", String.class)); Assert.assertEquals("< abc & def > \u0001", eval.eval( variables, "${str:unescapeXML(\"< abc & def > \")}", String.class ) ); } @Test public void testUnescapeJava() throws Exception { ELEvaluator eval = new ELEvaluator("testUnescapeJava", StringEL.class); ELVariables variables = new ELVariables(); Assert.assertEquals("\n", eval.eval(variables, "${str:unescapeJava(\"\\\\n\")}", String.class)); } @Test public void testUuid() throws Exception { final String UUID_FORMAT = "^[0-9a-z]{8}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{12}$"; ELEvaluator eval = new ELEvaluator("testUuid", StringEL.class); ELVariables variables = new ELVariables(); String uuid = eval.eval(variables, "${uuid:uuid()}", String.class); Assert.assertNotNull(uuid); Assert.assertTrue("UUID does not match expected format: " + uuid, uuid.matches(UUID_FORMAT)); String uuid2 = eval.eval(variables, "${uuid:uuid()}", String.class); Assert.assertNotNull(uuid); Assert.assertTrue("UUID does not match expected format: " + uuid, uuid.matches(UUID_FORMAT)); Assert.assertNotEquals(uuid, uuid2); } }