diff --git a/CHANGELOG.md b/CHANGELOG.md index c45c09f976..7dab080f1e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ #### Version 0.9.6 (TBD) * Fixed a bug that caused a `ParseException` to be thrown when trying to use a `Criteria` object containing a string value wrapped in single or double quotes out of necessity (i.e. because the value contained a keyword). This bug happened because the wrapping quotes were dropped by Concourse Server when parsing the `Criteria`. +* Fixed a bug where the CCL parser failed to handle some Unicode quote characters. #### Version 0.9.5 (December 30, 2018) * Fixed a bug where some of the `ManagedConcourseServer#get` methods in the `concourse-ete-test-core` package called the wrong upstream method of the Concourse Server instance under management. This had the effect of causing a runtime `ClassCastException` when trying to use those methods. diff --git a/concourse-driver-java/build.gradle b/concourse-driver-java/build.gradle index 7de10443ed..76ca9b2970 100644 --- a/concourse-driver-java/build.gradle +++ b/concourse-driver-java/build.gradle @@ -25,7 +25,7 @@ dependencies { compile 'org.slf4j:log4j-over-slf4j:1.7.5' compile 'org.slf4j:jcl-over-slf4j:1.7.5' compile 'com.google.code.gson:gson:2.5' - compile group: 'com.cinchapi', name: 'ccl', version:'2.5.1' + compile group: 'com.cinchapi', name: 'ccl', version:'2.5.2' testCompile project(':concourse-unit-test-core') testCompile 'com.github.marschall:memoryfilesystem:0.9.0' diff --git a/concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/Language.java b/concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/Language.java index fc41344e3d..34269c2ad0 100644 --- a/concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/Language.java +++ b/concourse-driver-java/src/main/java/com/cinchapi/concourse/lang/Language.java @@ -26,6 +26,7 @@ import com.cinchapi.ccl.grammar.TimestampSymbol; import com.cinchapi.ccl.grammar.ValueSymbol; import com.cinchapi.common.base.AnyStrings; +import com.cinchapi.common.reflect.Reflection; import com.cinchapi.concourse.thrift.TCriteria; import com.cinchapi.concourse.thrift.TSymbol; import com.cinchapi.concourse.thrift.TSymbolType; @@ -39,6 +40,13 @@ */ public final class Language { + /** + * The character that indicates a String should be treated as a + * {@link com.cinchapi.concourse.Tag}. + */ + private static final char TAG_MARKER = Reflection.getStatic("TAG_MARKER", + Convert.class); // (authorized) + /** * Translate the {@link TSymbol} to its Java analog. * @@ -55,7 +63,8 @@ else if(tsymbol.getType() == TSymbolType.KEY) { else if(tsymbol.getType() == TSymbolType.VALUE) { Object symbol = Convert.stringToJava(tsymbol.getSymbol()); if(symbol instanceof String && !symbol.equals(tsymbol.getSymbol()) - && AnyStrings.isWithinQuotes(tsymbol.getSymbol())) { + && AnyStrings.isWithinQuotes(tsymbol.getSymbol(), + TAG_MARKER)) { // CON-634: This is an obscure corner case where the surrounding // quotes on the original tsymbol were necessary to escape a // keyword, but got dropped because of the logic in diff --git a/concourse-integration-tests/src/test/java/com/cinchapi/concourse/bugrepro/CON635.java b/concourse-integration-tests/src/test/java/com/cinchapi/concourse/bugrepro/CON635.java new file mode 100644 index 0000000000..836036e406 --- /dev/null +++ b/concourse-integration-tests/src/test/java/com/cinchapi/concourse/bugrepro/CON635.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2013-2019 Cinchapi Inc. + * + * Licensed 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.cinchapi.concourse.bugrepro; + +import org.junit.Assert; +import org.junit.Test; + +import com.cinchapi.concourse.lang.Criteria; +import com.cinchapi.concourse.test.ConcourseIntegrationTest; +import com.cinchapi.concourse.thrift.Operator; + +/** + * Repro of http://jira.cinchapi.com/browse/CON-635 + * + * @author Jeff Nelson + */ +public class CON635 extends ConcourseIntegrationTest { + + @Test + public void repro1() { + client.find(Criteria.where().key("foo").operator(Operator.EQUALS) + .value("Foo’s")); + Assert.assertTrue(true); // lack of Exception means test passes + } + + @Test + public void repor2() { + client.find(Criteria.where().key("foo").operator(Operator.EQUALS) + .value("“A and B”")); + Assert.assertTrue(true); // lack of Exception means test passes + } + +}