diff --git a/CHANGES.txt b/CHANGES.txt index 1ccd936a868..48ca7341a59 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -512,6 +512,10 @@ Bug fixes 24. LUCENE-1819: MatchAllDocsQuery.toString(field) should produce output that is parsable by the QueryParser. (John Wang, Mark Miller) +25. LUCENE-1836: Fix localization bug in the new query parser and add + new LocalizedTestCase as base class for localization junit tests. + (Robert Muir, Uwe Schindler via Michael Busch) + New features 1. LUCENE-1411: Added expert API to open an IndexWriter on a prior diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/standard/processors/ParametricRangeQueryNodeProcessor.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/standard/processors/ParametricRangeQueryNodeProcessor.java index a2f6832203b..4c2277e5b5f 100644 --- a/contrib/queryparser/src/java/org/apache/lucene/queryParser/standard/processors/ParametricRangeQueryNodeProcessor.java +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/standard/processors/ParametricRangeQueryNodeProcessor.java @@ -116,8 +116,7 @@ public class ParametricRangeQueryNodeProcessor extends QueryNodeProcessorImpl { String part2 = upper.getTextAsString(); try { - DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT, Locale - .getDefault()); + DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT, locale); df.setLenient(true); Date d1 = df.parse(part1); Date d2 = df.parse(part2); diff --git a/contrib/queryparser/src/test/org/apache/lucene/queryParser/standard/TestQPHelper.java b/contrib/queryparser/src/test/org/apache/lucene/queryParser/standard/TestQPHelper.java index 4c4569ef865..ac84d201566 100644 --- a/contrib/queryparser/src/test/org/apache/lucene/queryParser/standard/TestQPHelper.java +++ b/contrib/queryparser/src/test/org/apache/lucene/queryParser/standard/TestQPHelper.java @@ -23,7 +23,10 @@ import java.text.Collator; import java.text.DateFormat; import java.util.Calendar; import java.util.Date; +import java.util.GregorianCalendar; import java.util.HashMap; +import java.util.HashSet; +import java.util.Arrays; import java.util.List; import java.util.Locale; import java.util.Map; @@ -73,7 +76,7 @@ import org.apache.lucene.search.TermRangeQuery; import org.apache.lucene.search.WildcardQuery; import org.apache.lucene.store.RAMDirectory; import org.apache.lucene.store.MockRAMDirectory; -import org.apache.lucene.util.LuceneTestCase; +import org.apache.lucene.util.LocalizedTestCase; /** * This test case is a copy of the core Lucene query parser test, it was adapted @@ -81,7 +84,15 @@ import org.apache.lucene.util.LuceneTestCase; * * Tests QueryParser. */ -public class TestQPHelper extends LuceneTestCase { +public class TestQPHelper extends LocalizedTestCase { + + public TestQPHelper(String name) { + super(name, new HashSet(Arrays.asList(new String[]{ + "testLegacyDateRange", "testDateRange", + "testCJK", "testNumber", "testFarsiRangeCollating", + "testLocalDateFormat" + }))); + } public static Analyzer qpAnalyzer = new QPTestAnalyzer(); @@ -649,11 +660,19 @@ public class TestQPHelper extends LuceneTestCase { return DateTools.dateToString(d, resolution); } } + + private String escapeDateString(String s) { + if (s.contains(" ")) { + return "\"" + s + "\""; + } else { + return s; + } + } private String getLocalizedDate(int year, int month, int day, boolean extendLastDate) { DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT); - Calendar calendar = Calendar.getInstance(); + Calendar calendar = new GregorianCalendar(); calendar.set(year, month, day); if (extendLastDate) { calendar.set(Calendar.HOUR_OF_DAY, 23); @@ -668,20 +687,20 @@ public class TestQPHelper extends LuceneTestCase { public void testLegacyDateRange() throws Exception { String startDate = getLocalizedDate(2002, 1, 1, false); String endDate = getLocalizedDate(2002, 1, 4, false); - Calendar endDateExpected = Calendar.getInstance(); + Calendar endDateExpected = new GregorianCalendar(); endDateExpected.set(2002, 1, 4, 23, 59, 59); endDateExpected.set(Calendar.MILLISECOND, 999); - assertQueryEquals("[ " + startDate + " TO " + endDate + "]", null, "[" + assertQueryEquals("[ " + escapeDateString(startDate) + " TO " + escapeDateString(endDate) + "]", null, "[" + getLegacyDate(startDate) + " TO " + DateField.dateToString(endDateExpected.getTime()) + "]"); - assertQueryEquals("{ " + startDate + " " + endDate + " }", null, "{" + assertQueryEquals("{ " + escapeDateString(startDate) + " " + escapeDateString(endDate) + " }", null, "{" + getLegacyDate(startDate) + " TO " + getLegacyDate(endDate) + "}"); } public void testDateRange() throws Exception { String startDate = getLocalizedDate(2002, 1, 1, false); String endDate = getLocalizedDate(2002, 1, 4, false); - Calendar endDateExpected = Calendar.getInstance(); + Calendar endDateExpected = new GregorianCalendar(); endDateExpected.set(2002, 1, 4, 23, 59, 59); endDateExpected.set(Calendar.MILLISECOND, 999); final String defaultField = "default"; @@ -727,10 +746,10 @@ public class TestQPHelper extends LuceneTestCase { public void assertDateRangeQueryEquals(StandardQueryParser qp, String field, String startDate, String endDate, Date endDateInclusive, DateTools.Resolution resolution) throws Exception { - assertQueryEquals(qp, field, field + ":[" + startDate + " TO " + endDate + assertQueryEquals(qp, field, field + ":[" + escapeDateString(startDate) + " TO " + escapeDateString(endDate) + "]", "[" + getDate(startDate, resolution) + " TO " + getDate(endDateInclusive, resolution) + "]"); - assertQueryEquals(qp, field, field + ":{" + startDate + " TO " + endDate + assertQueryEquals(qp, field, field + ":{" + escapeDateString(startDate) + " TO " + escapeDateString(endDate) + "}", "{" + getDate(startDate, resolution) + " TO " + getDate(endDate, resolution) + "}"); } @@ -1152,7 +1171,7 @@ public class TestQPHelper extends LuceneTestCase { int hour, int minute, int second, IndexWriter iw) throws IOException { Document d = new Document(); d.add(new Field("f", content, Field.Store.YES, Field.Index.ANALYZED)); - Calendar cal = Calendar.getInstance(); + Calendar cal = Calendar.getInstance(Locale.ENGLISH); cal.set(year, month - 1, day, hour, minute, second); d.add(new Field("date", DateField.dateToString(cal.getTime()), Field.Store.YES, Field.Index.NOT_ANALYZED)); diff --git a/src/test/org/apache/lucene/util/LocalizedTestCase.java b/src/test/org/apache/lucene/util/LocalizedTestCase.java new file mode 100644 index 00000000000..712e9ae3872 --- /dev/null +++ b/src/test/org/apache/lucene/util/LocalizedTestCase.java @@ -0,0 +1,108 @@ +package org.apache.lucene.util; + +/** + * 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. + */ + +import java.util.Locale; +import java.util.Set; + +/** + * Base test class for Lucene test classes that test Locale-sensitive behavior. + *

+ * This class will run tests under the default Locale, but then will also run + * tests under all available JVM locales. This is helpful to ensure tests will + * not fail under a different environment. + *

+ */ +public abstract class LocalizedTestCase extends LuceneTestCase { + /** + * Before changing the default Locale, save the default Locale here so that it + * can be restored. + */ + private final Locale defaultLocale = Locale.getDefault(); + + /** + * The locale being used as the system default Locale + */ + private Locale locale; + + /** + * An optional limited set of testcases that will run under different Locales. + */ + private final Set testWithDifferentLocales; + + public LocalizedTestCase() { + super(); + testWithDifferentLocales = null; + } + + public LocalizedTestCase(String name) { + super(name); + testWithDifferentLocales = null; + } + + public LocalizedTestCase(Set testWithDifferentLocales) { + super(); + this.testWithDifferentLocales = testWithDifferentLocales; + } + + public LocalizedTestCase(String name, Set testWithDifferentLocales) { + super(name); + this.testWithDifferentLocales = testWithDifferentLocales; + } + + // @Override + protected void setUp() throws Exception { + super.setUp(); + Locale.setDefault(locale); + } + + // @Override + protected void tearDown() throws Exception { + Locale.setDefault(defaultLocale); + super.tearDown(); + } + + // @Override + public void runBare() throws Throwable { + // Do the test with the default Locale (default) + try { + locale = defaultLocale; + super.runBare(); + } catch (Throwable e) { + System.out.println("Test failure of '" + getName() + + "' occurred with the default Locale " + locale); + throw e; + } + + if (testWithDifferentLocales == null + || testWithDifferentLocales.contains(getName())) { + // Do the test again under different Locales + Locale systemLocales[] = Locale.getAvailableLocales(); + for (int i = 0; i < systemLocales.length; i++) { + try { + locale = systemLocales[i]; + super.runBare(); + } catch (Throwable e) { + System.out.println("Test failure of '" + getName() + + "' occurred under a different Locale " + locale); + throw e; + } + } + } + } +}