Skip to content

Commit c2c6b43

Browse files
asolntsevandreastt
authored andcommitted
java: extract method Select.escapeQuotes to a separate class Quotes
Signed-off-by: Andreas Tolfsen <[email protected]>
1 parent 51b5fec commit c2c6b43

File tree

7 files changed

+224
-305
lines changed

7 files changed

+224
-305
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/*
2+
Copyright 2015 Software Freedom Conservancy
3+
Copyright 2007-2009 Selenium committers
4+
5+
Licensed under the Apache License, Version 2.0 (the "License");
6+
you may not use this file except in compliance with the License.
7+
You may obtain a copy of the License at
8+
9+
http://www.apache.org/licenses/LICENSE-2.0
10+
11+
Unless required by applicable law or agreed to in writing, software
12+
distributed under the License is distributed on an "AS IS" BASIS,
13+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
See the License for the specific language governing permissions and
15+
limitations under the License.
16+
*/
17+
18+
package org.openqa.selenium.support.ui;
19+
20+
public class Quotes {
21+
22+
/**
23+
* Convert strings with both quotes and ticks into a valid xpath component
24+
*
25+
* For example,
26+
*
27+
* <p>
28+
* {@code foo} will be converted to {@code "foo"},
29+
* </p>
30+
* <p>
31+
* {@code f"oo} will be converted to {@code 'f"oo'},
32+
* </p>
33+
* <p>
34+
* {@code foo'"bar} will be converted to {@code concat("foo'", '"', "bar")}
35+
* </p>
36+
*
37+
* @param toEscape a text to escape quotes in, e.g. {@code "f'oo"}
38+
* @return the same text with escaped quoted, e.g. {@code "\"f'oo\""}
39+
*/
40+
public static String escape(String toEscape) {
41+
if (toEscape.contains("\"") && toEscape.contains("'")) {
42+
boolean quoteIsLast = false;
43+
if (toEscape.lastIndexOf("\"") == toEscape.length() - 1) {
44+
quoteIsLast = true;
45+
}
46+
String[] substringsWithoutQuotes = toEscape.split("\"");
47+
48+
StringBuilder quoted = new StringBuilder("concat(");
49+
for (int i = 0; i < substringsWithoutQuotes.length; i++) {
50+
quoted.append("\"").append(substringsWithoutQuotes[i]).append("\"");
51+
quoted
52+
.append(((i == substringsWithoutQuotes.length - 1) ? (quoteIsLast ? ", '\"')" : ")")
53+
: ", '\"', "));
54+
}
55+
return quoted.toString();
56+
}
57+
58+
// Escape string with just a quote into being single quoted: f"oo -> 'f"oo'
59+
if (toEscape.contains("\"")) {
60+
return String.format("'%s'", toEscape);
61+
}
62+
63+
// Otherwise return the quoted string
64+
return String.format("\"%s\"", toEscape);
65+
}
66+
}

Diff for: java/client/src/org/openqa/selenium/support/ui/Select.java

+13-43
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/*
2+
Copyright 2015 Software Freedom Conservancy
23
Copyright 2007-2009 Selenium committers
34
45
Licensed under the Apache License, Version 2.0 (the "License");
@@ -111,7 +112,7 @@ public WebElement getFirstSelectedOption() {
111112
public void selectByVisibleText(String text) {
112113
// try to find the option via XPATH ...
113114
List<WebElement> options =
114-
element.findElements(By.xpath(".//option[normalize-space(.) = " + escapeQuotes(text) + "]"));
115+
element.findElements(By.xpath(".//option[normalize-space(.) = " + Quotes.escape(text) + "]"));
115116

116117
boolean matched = false;
117118
for (WebElement option : options) {
@@ -132,7 +133,7 @@ public void selectByVisibleText(String text) {
132133
// get candidates via XPATH ...
133134
candidates =
134135
element.findElements(By.xpath(".//option[contains(., " +
135-
escapeQuotes(subStringWithoutSpace) + ")]"));
136+
Quotes.escape(subStringWithoutSpace) + ")]"));
136137
}
137138
for (WebElement option : candidates) {
138139
if (text.equals(option.getText())) {
@@ -163,7 +164,7 @@ private String getLongestSubstringWithoutSpace(String s) {
163164
}
164165

165166
/**
166-
* Select the option at the given index. This is done by examing the "index" attribute of an
167+
* Select the option at the given index. This is done by examining the "index" attribute of an
167168
* element, and not merely by counting.
168169
*
169170
* @param index The option at this index will be selected
@@ -197,10 +198,8 @@ public void selectByIndex(int index) {
197198
* @throws NoSuchElementException If no matching option elements are found
198199
*/
199200
public void selectByValue(String value) {
200-
StringBuilder builder = new StringBuilder(".//option[@value = ");
201-
builder.append(escapeQuotes(value));
202-
builder.append("]");
203-
List<WebElement> options = element.findElements(By.xpath(builder.toString()));
201+
List<WebElement> options = element.findElements(By.xpath(
202+
".//option[@value = " + Quotes.escape(value) + "]"));
204203

205204
boolean matched = false;
206205
for (WebElement option : options) {
@@ -244,10 +243,9 @@ public void deselectAll() {
244243
* @throws NoSuchElementException If no matching option elements are found
245244
*/
246245
public void deselectByValue(String value) {
247-
StringBuilder builder = new StringBuilder(".//option[@value = ");
248-
builder.append(escapeQuotes(value));
249-
builder.append("]");
250-
List<WebElement> options = element.findElements(By.xpath(builder.toString()));
246+
List<WebElement> options = element.findElements(By.xpath(
247+
".//option[@value = " + Quotes.escape(value) + "]"));
248+
251249
for (WebElement option : options) {
252250
if (option.isSelected()) {
253251
option.click();
@@ -256,7 +254,7 @@ public void deselectByValue(String value) {
256254
}
257255

258256
/**
259-
* Deselect the option at the given index. This is done by examing the "index" attribute of an
257+
* Deselect the option at the given index. This is done by examining the "index" attribute of an
260258
* element, and not merely by counting.
261259
*
262260
* @param index The option at this index will be deselected
@@ -282,44 +280,16 @@ public void deselectByIndex(int index) {
282280
* @throws NoSuchElementException If no matching option elements are found
283281
*/
284282
public void deselectByVisibleText(String text) {
285-
StringBuilder builder = new StringBuilder(".//option[normalize-space(.) = ");
286-
builder.append(escapeQuotes(text));
287-
builder.append("]");
288-
List<WebElement> options = element.findElements(By.xpath(builder.toString()));
283+
List<WebElement> options = element.findElements(By.xpath(
284+
".//option[normalize-space(.) = " + Quotes.escape(text) + "]"));
285+
289286
for (WebElement option : options) {
290287
if (option.isSelected()) {
291288
option.click();
292289
}
293290
}
294291
}
295292

296-
protected String escapeQuotes(String toEscape) {
297-
// Convert strings with both quotes and ticks into: foo'"bar -> concat("foo'", '"', "bar")
298-
if (toEscape.indexOf("\"") > -1 && toEscape.indexOf("'") > -1) {
299-
boolean quoteIsLast = false;
300-
if (toEscape.lastIndexOf("\"") == toEscape.length() - 1) {
301-
quoteIsLast = true;
302-
}
303-
String[] substrings = toEscape.split("\"");
304-
305-
StringBuilder quoted = new StringBuilder("concat(");
306-
for (int i = 0; i < substrings.length; i++) {
307-
quoted.append("\"").append(substrings[i]).append("\"");
308-
quoted
309-
.append(((i == substrings.length - 1) ? (quoteIsLast ? ", '\"')" : ")") : ", '\"', "));
310-
}
311-
return quoted.toString();
312-
}
313-
314-
// Escape string with just a quote into being single quoted: f"oo -> 'f"oo'
315-
if (toEscape.indexOf("\"") > -1) {
316-
return String.format("'%s'", toEscape);
317-
}
318-
319-
// Otherwise return the quoted string
320-
return String.format("\"%s\"", toEscape);
321-
}
322-
323293
private void setSelected(WebElement option) {
324294
if (!option.isSelected()) {
325295
option.click();

Diff for: java/client/src/org/openqa/selenium/support/ui/build.desc

+1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ java_library(name = "components",
3232
java_library(name = "elements",
3333
srcs = [
3434
"Select.java",
35+
"Quotes.java",
3536
"UnexpectedTagNameException.java",
3637
],
3738
deps = [

Diff for: java/client/test/org/openqa/selenium/support/SmallTests.java

+2
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import org.openqa.selenium.support.ui.ExpectedConditionsTest;
2727
import org.openqa.selenium.support.ui.FluentWaitTest;
2828
import org.openqa.selenium.support.ui.LoadableComponentTest;
29+
import org.openqa.selenium.support.ui.QuotesTest;
2930
import org.openqa.selenium.support.ui.SelectTest;
3031
import org.openqa.selenium.support.ui.SlowLoadableComponentTest;
3132
import org.openqa.selenium.support.ui.WebDriverWaitTest;
@@ -49,6 +50,7 @@
4950
LocatingElementListHandlerTest.class,
5051
PageFactoryTest.class,
5152
SelectTest.class,
53+
QuotesTest.class,
5254
SlowLoadableComponentTest.class,
5355
ThreadGuardTest.class,
5456
WebDriverWaitTest.class
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
Copyright 2015 Software Freedom Conservancy
3+
Copyright 2007-2009 Selenium committers
4+
5+
Licensed under the Apache License, Version 2.0 (the "License");
6+
you may not use this file except in compliance with the License.
7+
You may obtain a copy of the License at
8+
9+
http://www.apache.org/licenses/LICENSE-2.0
10+
11+
Unless required by applicable law or agreed to in writing, software
12+
distributed under the License is distributed on an "AS IS" BASIS,
13+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
See the License for the specific language governing permissions and
15+
limitations under the License.
16+
*/
17+
18+
package org.openqa.selenium.support.ui;
19+
20+
import static org.junit.Assert.assertEquals;
21+
22+
import org.junit.Test;
23+
import org.junit.runner.RunWith;
24+
import org.junit.runners.JUnit4;
25+
26+
@RunWith(JUnit4.class)
27+
public class QuotesTest {
28+
@Test
29+
public void shouldConvertAnUnquotedStringIntoOneWithQuotes() {
30+
assertEquals("\"foo\"", Quotes.escape("foo"));
31+
}
32+
33+
@Test
34+
public void shouldConvertAStringWithATickIntoOneWithQuotes() {
35+
assertEquals("\"f'oo\"", Quotes.escape("f'oo"));
36+
}
37+
38+
@Test
39+
public void shouldConvertAStringWithAQuotIntoOneWithTicks() {
40+
assertEquals("'f\"oo'", Quotes.escape("f\"oo"));
41+
}
42+
43+
@Test
44+
public void shouldProvideConcatenatedStringsWhenStringToEscapeContainsTicksAndQuotes() {
45+
assertEquals("concat(\"f\", '\"', \"o'o\")", Quotes.escape("f\"o'o"));
46+
}
47+
48+
/**
49+
* Tests that Quotes.escape returns concatenated strings when the given
50+
* string contains a tick and and ends with a quote.
51+
*/
52+
@Test
53+
public void shouldProvideConcatenatedStringsWhenStringEndsWithQuote() {
54+
assertEquals("concat(\"Bar \", '\"', \"Rock'n'Roll\", '\"')", Quotes.escape(
55+
"Bar \"Rock'n'Roll\""));
56+
}
57+
}

Diff for: java/client/test/org/openqa/selenium/support/ui/SelectElementTest.java

+6-54
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
2+
Copyright 2015 Software Freedom Conservancy
23
Copyright 2012 Selenium committers
3-
Copyright 2012 Software Freedom Conservancy
44
55
Licensed under the Apache License, Version 2.0 (the "License");
66
you may not use this file except in compliance with the License.
@@ -18,6 +18,11 @@
1818

1919
package org.openqa.selenium.support.ui;
2020

21+
import static org.junit.Assert.assertEquals;
22+
import static org.junit.Assert.assertFalse;
23+
import static org.junit.Assert.assertTrue;
24+
import static org.openqa.selenium.testing.Ignore.Driver.MARIONETTE;
25+
2126
import org.junit.Before;
2227
import org.junit.Test;
2328
import org.openqa.selenium.By;
@@ -27,10 +32,6 @@
2732

2833
import java.util.List;
2934

30-
import static org.junit.Assert.*;
31-
32-
import static org.openqa.selenium.testing.Ignore.Driver.MARIONETTE;
33-
3435
public class SelectElementTest extends JUnit4TestBase {
3536

3637
@Before
@@ -257,53 +258,4 @@ public void shouldAllowOptionsToBeDeselectedByReturnedValue() {
257258

258259
assertEquals(1,returnedOptions.size());
259260
}
260-
261-
@Test
262-
public void shouldConvertAnUnquotedStringIntoOneWithQuotes() {
263-
WebElement selectElement = driver.findElement(By.name("multi"));
264-
Select select = new Select(selectElement);
265-
String result = select.escapeQuotes("foo");
266-
267-
assertEquals("\"foo\"", result);
268-
}
269-
270-
@Test
271-
public void shouldConvertAStringWithATickIntoOneWithQuotes() {
272-
WebElement selectElement = driver.findElement(By.name("multi"));
273-
Select select = new Select(selectElement);
274-
String result = select.escapeQuotes("f'oo");
275-
276-
assertEquals("\"f'oo\"", result);
277-
}
278-
279-
@Test
280-
public void shouldConvertAStringWithAQuotIntoOneWithTicks() {
281-
WebElement selectElement = driver.findElement(By.name("multi"));
282-
Select select = new Select(selectElement);
283-
String result = select.escapeQuotes("f\"oo");
284-
285-
assertEquals("'f\"oo'", result);
286-
}
287-
288-
@Test
289-
public void shouldProvideConcatenatedStringsWhenStringToEscapeContainsTicksAndQuotes() {
290-
WebElement selectElement = driver.findElement(By.name("multi"));
291-
Select select = new Select(selectElement);
292-
String result = select.escapeQuotes("f\"o'o");
293-
294-
assertEquals("concat(\"f\", '\"', \"o'o\")", result);
295-
}
296-
297-
/**
298-
* Tests that escapeQuotes returns concatenated strings when the given
299-
* string contains a tick and and ends with a quote.
300-
*/
301-
@Test
302-
public void shouldProvideConcatenatedStringsWhenStringEndsWithQuote() {
303-
WebElement selectElement = driver.findElement(By.name("multi"));
304-
Select select = new Select(selectElement);
305-
String result = select.escapeQuotes("Bar \"Rock'n'Roll\"");
306-
307-
assertEquals("concat(\"Bar \", '\"', \"Rock'n'Roll\", '\"')", result);
308-
}
309261
}

0 commit comments

Comments
 (0)