Am 21. November 2017 22:23:32 MEZ schrieb Philippe Mouawad <philippe.moua...@gmail.com>: >Hi Felix, >In this case CAMEL_CASE implementations are wrong. >Your conception look indeed closer to what I was usually seeing. >Shall I fix it ?
I have a few more questions ;) What shall we do with umlauts? If we handle umlauts, how do we specify the encoding? Should we support snake case, as well? > >Do you think CAMEL_CASE and CAMEL_CASE_FIRST_LOWER are clear enough ? >Or should we name them: > > - UPPER_CAMEL_CASE > - LOWER_CAMEL_CASE > >As per: >https://en.wikipedia.org/wiki/Camel_case I think it is a good idea to follow the wording used in Wikipedia. >Thanks > > > >On Tue, Nov 21, 2017 at 9:59 PM, Felix Schumacher <felix.schumacher@ >internetallee.de> wrote: > >> Am 20.11.2017 um 20:50 schrieb pmoua...@apache.org: >> >>> Author: pmouawad >>> Date: Mon Nov 20 19:50:51 2017 >>> New Revision: 1815838 >>> >>> URL: http://svn.apache.org/viewvc?rev=1815838&view=rev >>> Log: >>> Bug 61759 - New __changeCase function >>> Contributed by Orimarko >>> Bugzilla Id: 61759 >>> >>> Added: >>> >jmeter/trunk/src/functions/org/apache/jmeter/functions/ChangeCase.java >>> (with props) >>> >jmeter/trunk/test/src/org/apache/jmeter/functions/TestChangeCase.java >>> (with props) >>> Modified: >>> jmeter/trunk/xdocs/changes.xml >>> jmeter/trunk/xdocs/usermanual/functions.xml >>> >>> Added: jmeter/trunk/src/functions/org/apache/jmeter/functions/Chang >>> eCase.java >>> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/functions/org/ >>> apache/jmeter/functions/ChangeCase.java?rev=1815838&view=auto >>> ============================================================ >>> ================== >>> --- >jmeter/trunk/src/functions/org/apache/jmeter/functions/ChangeCase.java >>> (added) >>> +++ >jmeter/trunk/src/functions/org/apache/jmeter/functions/ChangeCase.java >>> Mon Nov 20 19:50:51 2017 >>> @@ -0,0 +1,175 @@ >>> +/* >>> + * 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.jmeter.functions; >>> + >>> +import java.util.Collection; >>> +import java.util.EnumSet; >>> +import java.util.LinkedList; >>> +import java.util.List; >>> +import java.util.regex.Pattern; >>> + >>> +import org.apache.commons.lang3.StringUtils; >>> +import org.apache.jmeter.engine.util.CompoundVariable; >>> +import org.apache.jmeter.samplers.SampleResult; >>> +import org.apache.jmeter.samplers.Sampler; >>> +import org.apache.jmeter.util.JMeterUtils; >>> +import org.slf4j.Logger; >>> +import org.slf4j.LoggerFactory; >>> + >>> +/** >>> + * Change Case Function >>> + * >>> + * Support String manipulations of: >>> + * <ul> >>> + * <li>upper case</li> >>> + * <li>lower case</li> >>> + * <li>capitalize</li> >>> + * <li>camel cases</li> >>> + * <li></li> >>> + * >>> + * >>> + * @since 4.0 >>> + * >>> + */ >>> +public class ChangeCase extends AbstractFunction { >>> + >>> + private static final Pattern NOT_ALPHANUMERIC_REGEX = >>> + Pattern.compile("[^a-zA-Z]"); >>> + private static final Logger LOGGER = >LoggerFactory.getLogger(Change >>> Case.class); >>> + private static final List<String> DESC = new LinkedList<>(); >>> + private static final String KEY = "__changeCase"; >>> + >>> + private static final int MIN_PARAMETER_COUNT = 1; >>> + private static final int MAX_PARAMETER_COUNT = 3; >>> + >>> + static { >>> + DESC.add(JMeterUtils.getResString("change_case_string")); >>> + DESC.add(JMeterUtils.getResString("change_case_mode")); >>> + DESC.add(JMeterUtils.getResString("function_name_paropt")); >>> + } >>> + >>> + private CompoundVariable[] values; >>> + >>> + @Override >>> + public String execute(SampleResult previousResult, Sampler >>> currentSampler) throws InvalidVariableException { >>> + String originalString = values[0].execute(); >>> + String mode = ChangeCaseMode.UPPER.getName(); // default >>> + if (values.length > 1) { >>> + mode = values[1].execute(); >>> + } >>> + String targetString = changeCase(originalString, mode); >>> + addVariableValue(targetString, values, 2); >>> + return targetString; >>> + } >>> + >>> + protected String changeCase(String originalString, String mode) >{ >>> + String targetString = originalString; >>> + // mode is case insensitive, allow upper for example >>> + ChangeCaseMode changeCaseMode = >ChangeCaseMode.typeOf(mode.toU >>> pperCase()); >>> + if (changeCaseMode != null) { >>> + switch (changeCaseMode) { >>> + case UPPER: >>> + targetString = >StringUtils.upperCase(originalString); >>> + break; >>> + case LOWER: >>> + targetString = >StringUtils.lowerCase(originalString); >>> + break; >>> + case CAPITALIZE: >>> + targetString = >StringUtils.capitalize(originalString); >>> + break; >>> + case CAMEL_CASE: >>> + targetString = camel(originalString, false); >>> + break; >>> + case CAMEL_CASE_FIRST_LOWER: >>> + targetString = camel(originalString, true); >>> + break; >>> + default: >>> + // default not doing nothing to string >>> + } >>> + } else { >>> + LOGGER.error("Unknown mode {}, returning {}Â >unchanged", >>> mode, targetString); >>> + } >>> + return targetString; >>> + } >>> + >>> + @Override >>> + public void setParameters(Collection<CompoundVariable> >parameters) >>> throws InvalidVariableException { >>> + checkParameterCount(parameters, MIN_PARAMETER_COUNT, >>> MAX_PARAMETER_COUNT); >>> + values = parameters.toArray(new >CompoundVariable[parameters.si >>> ze()]); >>> + } >>> + >>> + @Override >>> + public String getReferenceKey() { >>> + return KEY; >>> + } >>> + >>> + @Override >>> + public List<String> getArgumentDesc() { >>> + return DESC; >>> + } >>> + >>> + private static String camel(String str, boolean >isFirstCapitalized) { >>> + StringBuilder builder = new StringBuilder(str.length()); >>> + String[] tokens = NOT_ALPHANUMERIC_REGEX.split(str); >>> + for (int i = 0; i < tokens.length; i++) { >>> + if(i == 0) { >>> + builder.append(isFirstCapitalized ? tokens[0]: >>> + StringUtils.capitalize(tokens[i])); >>> + } else { >>> + builder.append(StringUtils.capitalize(tokens[i])); >>> + } >>> + } >>> + return builder.toString(); >>> + } >>> + >>> + /** >>> + * ChangeCase Modes >>> + * >>> + * Modes for different cases >>> + * >>> + */ >>> + public enum ChangeCaseMode { >>> + UPPER("UPPER"), LOWER("LOWER"), CAPITALIZE("CAPITALIZE"), >>> CAMEL_CASE("CAMEL_CASE"), CAMEL_CASE_FIRST_LOWER( >>> + "CAMEL_CASE_FIRST_LOWER"); >>> + private String mode; >>> + >>> + private ChangeCaseMode(String mode) { >>> + this.mode = mode; >>> + } >>> + >>> + public String getName() { >>> + return this.mode; >>> + } >>> + >>> + /** >>> + * Get ChangeCaseMode by mode >>> + * >>> + * @param mode >>> + * @return relevant ChangeCaseMode >>> + */ >>> + public static ChangeCaseMode typeOf(String mode) { >>> + EnumSet<ChangeCaseMode> allOf = >>> EnumSet.allOf(ChangeCaseMode.class); >>> + for (ChangeCaseMode zs : allOf) { >>> + if (zs.getName().equals(mode)) >>> + return zs; >>> + } >>> + return null; >>> + } >>> + } >>> +} >>> >>> Propchange: >jmeter/trunk/src/functions/org/apache/jmeter/functions/Chang >>> eCase.java >>> ------------------------------------------------------------ >>> ------------------ >>> svn:eol-style = native >>> >>> Propchange: >jmeter/trunk/src/functions/org/apache/jmeter/functions/Chang >>> eCase.java >>> ------------------------------------------------------------ >>> ------------------ >>> svn:mime-type = text/plain >>> >>> Added: jmeter/trunk/test/src/org/apache/jmeter/functions/TestChange >>> Case.java >>> URL: http://svn.apache.org/viewvc/jmeter/trunk/test/src/org/apach >>> e/jmeter/functions/TestChangeCase.java?rev=1815838&view=auto >>> ============================================================ >>> ================== >>> --- >jmeter/trunk/test/src/org/apache/jmeter/functions/TestChangeCase.java >>> (added) >>> +++ >jmeter/trunk/test/src/org/apache/jmeter/functions/TestChangeCase.java >>> Mon Nov 20 19:50:51 2017 >>> @@ -0,0 +1,138 @@ >>> +/* >>> + * 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.jmeter.functions; >>> + >>> +import static org.junit.Assert.assertEquals; >>> + >>> +import java.util.Collection; >>> +import java.util.LinkedList; >>> + >>> +import org.apache.jmeter.engine.util.CompoundVariable; >>> +import org.apache.jmeter.junit.JMeterTestCase; >>> +import org.apache.jmeter.samplers.SampleResult; >>> +import org.apache.jmeter.threads.JMeterContext; >>> +import org.apache.jmeter.threads.JMeterContextService; >>> +import org.apache.jmeter.threads.JMeterVariables; >>> +import org.junit.Before; >>> +import org.junit.Test; >>> + >>> +/** >>> + * Test{@link ChangeCase} ChangeCase >>> + * >>> + * @see ChangeCase >>> + * @since 4.0 >>> + */ >>> +public class TestChangeCase extends JMeterTestCase { >>> + >>> + protected AbstractFunction changeCase; >>> + private SampleResult result; >>> + >>> + private Collection<CompoundVariable> params; >>> + >>> + private JMeterVariables vars; >>> + >>> + private JMeterContext jmctx; >>> + >>> + @Before >>> + public void setUp() { >>> + changeCase = new ChangeCase(); >>> + result = new SampleResult(); >>> + jmctx = JMeterContextService.getContext(); >>> + String data = "dummy data"; >>> + result.setResponseData(data, null); >>> + vars = new JMeterVariables(); >>> + jmctx.setVariables(vars); >>> + jmctx.setPreviousResult(result); >>> + params = new LinkedList<>(); >>> + } >>> + >>> + @Test >>> + public void testParameterCountIsPropDefined() throws Exception >{ >>> + checkInvalidParameterCounts(changeCase, 1, 3); >>> + } >>> + >>> + @Test >>> + public void testChangeCase() throws Exception { >>> + params.add(new CompoundVariable("myUpperTest")); >>> + changeCase.setParameters(params); >>> + String returnValue = changeCase.execute(result, null); >>> + assertEquals("MYUPPERTEST", returnValue); >>> + } >>> + >>> + @Test >>> + public void testChangeCaseLower() throws Exception { >>> + params.add(new CompoundVariable("myUpperTest")); >>> + params.add(new CompoundVariable("LOWER")); >>> + changeCase.setParameters(params); >>> + String returnValue = changeCase.execute(result, null); >>> + assertEquals("myuppertest", returnValue); >>> + } >>> + >>> + @Test >>> + public void testChangeCaseWrongMode() throws Exception { >>> + params.add(new CompoundVariable("myUpperTest")); >>> + params.add(new CompoundVariable("Wrong")); >>> + changeCase.setParameters(params); >>> + String returnValue = changeCase.execute(result, null); >>> + assertEquals("myUpperTest", returnValue); >>> + } >>> + >>> + @Test >>> + public void testChangeCaseCamelCase() throws Exception { >>> + params.add(new CompoundVariable("ab-CD eF")); >>> + params.add(new CompoundVariable("CAMEL_CASE")); >>> + changeCase.setParameters(params); >>> + String returnValue = changeCase.execute(result, null); >>> + assertEquals("AbCDEF", returnValue); >>> + } >>> + >>> + @Test >>> + public void testChangeCaseCapitalize() throws Exception { >>> + params.add(new CompoundVariable("ab-CD eF")); >>> + params.add(new CompoundVariable("CAPITALIZE")); >>> + changeCase.setParameters(params); >>> + String returnValue = changeCase.execute(result, null); >>> + assertEquals("Ab-CD eF", returnValue); >>> + } >>> + >>> + @Test >>> + public void testChangeCaseCamelCaseFirstLower() throws >Exception { >>> + params.add(new CompoundVariable("ab-CD eF")); >>> + params.add(new CompoundVariable("camel_CASE_FIRST_LOWER")); >>> + changeCase.setParameters(params); >>> + String returnValue = changeCase.execute(result, null); >>> + assertEquals("abCDEF", returnValue); >>> + } >>> + >>> + @Test(expected=InvalidVariableException.class) >>> + public void testChangeCaseError() throws Exception { >>> + changeCase.setParameters(params); >>> + changeCase.execute(result, null); >>> + } >>> + >>> + @Test >>> + public void testChangeCaseWrongModeIgnore() throws Exception { >>> + params.add(new CompoundVariable("ab-CD eF")); >>> + params.add(new CompoundVariable("Wrong")); >>> + changeCase.setParameters(params); >>> + String returnValue = changeCase.execute(result, null); >>> + assertEquals("ab-CD eF", returnValue); >>> + } >>> + >>> +} >>> >>> Propchange: >jmeter/trunk/test/src/org/apache/jmeter/functions/TestChange >>> Case.java >>> ------------------------------------------------------------ >>> ------------------ >>> svn:eol-style = native >>> >>> Propchange: >jmeter/trunk/test/src/org/apache/jmeter/functions/TestChange >>> Case.java >>> ------------------------------------------------------------ >>> ------------------ >>> svn:mime-type = text/plain >>> >>> Modified: jmeter/trunk/xdocs/changes.xml >>> URL: http://svn.apache.org/viewvc/jmeter/trunk/xdocs/changes.xml? >>> rev=1815838&r1=1815837&r2=1815838&view=diff >>> ============================================================ >>> ================== >>> --- jmeter/trunk/xdocs/changes.xml [utf-8] (original) >>> +++ jmeter/trunk/xdocs/changes.xml [utf-8] Mon Nov 20 19:50:51 2017 >>> @@ -136,6 +136,7 @@ Summary >>> <li><bug>61724</bug>Add <code>__digest</code> function to >provide >>> computing of Hashes (SHA-XXX, MDX). Based on a contribution by >orimarko at >>> gmail.com</li> >>> <li><bug>61735</bug>Add <code>__dateTimeConvert</code> >function to >>> provide date formats conversions. Based on a contribution by >orimarko at >>> gmail.com</li> >>> <li><bug>61760</bug>Add <code>__isPropDefined</code> and >>> <code>__isVarDefined</code> functions to know if property or >variable >>> exist. Contributed by orimarko at gmail.com</li> >>> + <li><bug>61759</bug>Add <code>__changeCase</code> function to >change >>> different cases of a string. Based on a contribution by orimarko at >>> gmail.com</li> >>> </ul> >>> <h3>I18N</h3> >>> >>> Modified: jmeter/trunk/xdocs/usermanual/functions.xml >>> URL: http://svn.apache.org/viewvc/jmeter/trunk/xdocs/usermanual/f >>> unctions.xml?rev=1815838&r1=1815837&r2=1815838&view=diff >>> ============================================================ >>> ================== >>> --- jmeter/trunk/xdocs/usermanual/functions.xml (original) >>> +++ jmeter/trunk/xdocs/usermanual/functions.xml Mon Nov 20 19:50:51 >2017 >>> @@ -143,13 +143,14 @@ Alternatively, just use <code>/</code> i >>> <tr><td>Variables</td><td> <a >href="#__evalVar">evalVar</a></td><td>evaluate >>> an expression stored in a variable</td><td>2.3.1</td></tr> >>> <tr><td>Properties</td><td> <a >href="#__isVarDefined">isVarDefined</a> >>> </td><td>Test if a variable exists</td><td>4.0</td></tr> >>> <tr><td>Variables</td><td> <a >href="#__V">V</a></td><td>evaluate >>> a variable name</td><td>2.3RC3</td></tr> >>> - <tr><td>String</td><td> <a >href="#__regexFunction">regexFunction</a></td><td>parse >>> previous response using a regular expression</td><td>1.X</td></tr> >>> - <tr><td>String</td><td> <a href="#__escapeOroRegexpChars" >>> >escapeOroRegexpChars</a></td><td>quote meta chars used by ORO >regular >>> expression</td><td>2.9</td></tr> >>> <tr><td>String</td><td> <a >href="#__char">char</a></td><td>generate >>> Unicode char values from a list of numbers</td><td>2.3.3</td></tr> >>> - <tr><td>String</td><td> <a >href="#__unescape">unescape</a></td><td>Process >>> strings containing Java escapes (e.g. \n & >\t)</td><td>2.3.3</td></tr> >>> - <tr><td>String</td><td> <a >href="#__unescapeHtml">unescapeHtml</a></td><td>Decode >>> HTML-encoded strings</td><td>2.3.3</td></tr> >>> + <tr><td>String</td><td> <a >href="#__changeCase">changeCase</a></td><td>Change >>> case following different modes</td><td>4.0</td></tr> >>> <tr><td>String</td><td> <a >href="#__escapeHtml">escapeHtml</a></td><td>Encode >>> strings using HTML encoding</td><td>2.3.3</td></tr> >>> + <tr><td>String</td><td> <a href="#__escapeOroRegexpChars" >>> >escapeOroRegexpChars</a></td><td>quote meta chars used by ORO >regular >>> expression</td><td>2.9</td></tr> >>> <tr><td>String</td><td> <a >href="#__escapeXml">escapeXml</a></td><td>Encode >>> strings using XMl encoding</td><td>3.2</td></tr> >>> + <tr><td>String</td><td> <a >href="#__regexFunction">regexFunction</a></td><td>parse >>> previous response using a regular expression</td><td>1.X</td></tr> >>> + <tr><td>String</td><td> <a >href="#__unescape">unescape</a></td><td>Process >>> strings containing Java escapes (e.g. \n & >\t)</td><td>2.3.3</td></tr> >>> + <tr><td>String</td><td> <a >href="#__unescapeHtml">unescapeHtml</a></td><td>Decode >>> HTML-encoded strings</td><td>2.3.3</td></tr> >>> <tr><td>String</td><td> <a >href="#__urldecode">urldecode</a></td><td>Decode >>> a application/x-www-form-urlencoded string</td><td>2.10</td></tr> >>> <tr><td>String</td><td> <a >href="#__urlencode">urlencode</a></td><td>Encode >>> a string to a application/x-www-form-urlencoded >>> string</td><td>2.10</td></tr> >>> <tr><td>String</td><td> <a >href="#__TestPlanName">TestPlanName</a></td><td>Return >>> name of current test plan</td><td>2.6</td></tr> >>> @@ -1616,7 +1617,7 @@ becomes: >>> <property name="Name of variable" required="No">The name >of the >>> variable to set.</property> >>> </properties> >>> </component> >>> -<component index="§-num;.5.35" name="__isPropDefined"> >>> +<component index="§-num;.5.36" name="__isPropDefined"> >>> <description> >>> <p>The <code>__isPropDefined</code> function returns true >if >>> property exists or false if not.</p> >>> </description> >>> @@ -1626,7 +1627,7 @@ becomes: >>> </property> >>> </properties> >>> </component> >>> -<component index="§-num;.5.35" name="__isVarDefined"> >>> +<component index="§-num;.5.37" name="__isVarDefined"> >>> <description> >>> <p>The <code>__isVarDefined</code> function returns true >if >>> variable exists or false if not.</p> >>> </description> >>> @@ -1636,6 +1637,30 @@ becomes: >>> </property> >>> </properties> >>> </component> >>> +<component index="§-num;.5.38" name="__changeCase"> >>> + <description> >>> + <p>The change case function returns a string value which >>> + case has been changed following a specific mode. >>> + Result can optionally be saved in a JMeter variable.</p> >>> + </description> >>> + <properties> >>> + <property name="String to change case" required="Yes">The >String >>> + which case will be changed</property> >>> + <property name="change case mode" required="Yes"> >>> + The mode to be used to change case, for example for >ab-CD eF: >>> + <ul> >>> + <li><code>UPPER</code> result as AB-CD EF</li> >>> + <li><code>LOWER</code> result as ab-cd ed</li> >>> + <li><code>CAPITALIZE</code> result as Ab-CD eF</li> >>> + <li><code>CAMEL_CASE</code>result as AbCDEF</li> >>> >> Shouldn't this be AbCdEf? >> >>> + <li><code>CAMEL_CASE_FIRST_LOWER</code>result as >>> abCDEF</li> >>> >> and this abCdEf? >> >> Regards, >> Felix >> >> + </ul> >>> + <note>mode is case insensitive</note> >>> + </property> >>> + <property name="Name of variable" required="No">The name of >the >>> variable to set.</property> >>> + </properties> >>> +</component> >>> + >>> </subsection> >>> <subsection name="§-num;.6 Pre-defined Variables" >>> anchor="predefinedvars"> >>> >>> >>> >>