Skip to content

Commit

Permalink
Merge pull request #29 from bhamiltoncx/turkish
Browse files Browse the repository at this point in the history
Add Turkish path normalization
  • Loading branch information
cgdecker committed Jan 8, 2016
2 parents da62fd9 + fe85915 commit a68159d
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,7 @@ private ImmutableSet<PathNormalization> checkNormalizations(
normalization = n;
break;
case CASE_FOLD_UNICODE:
case CASE_FOLD_TURKISH:
case CASE_FOLD_ASCII:
checkNormalizationNotSet(n, caseFold);
caseFold = n;
Expand Down
30 changes: 27 additions & 3 deletions jimfs/src/main/java/com/google/common/jimfs/PathNormalization.java
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,6 @@ public String apply(String string) {
* Unicode case folding for case insensitive paths. Requires ICU4J on the classpath.
*/
CASE_FOLD_UNICODE(Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE) {
// TODO(cgdecker): This does default case folding, e.g. non-Turkish case folding.
// Should there be an option to use the Turkish-correct case folding instead?
@Override
public String apply(String string) {
try {
Expand All @@ -85,6 +83,26 @@ public String apply(String string) {
}
},

/**
* Unicode case folding for case insensitive paths using Turkic languages (Turkish, Azerbaijani).
* Requires ICU4J on the classpath.
*/
CASE_FOLD_TURKISH(-1) {
@Override
public String apply(String string) {
try {
return UCharacter.foldCase(string, UCharacter.FOLD_CASE_EXCLUDE_SPECIAL_I);
} catch (NoClassDefFoundError e) {
NoClassDefFoundError error =
new NoClassDefFoundError(
"PathNormalization.CASE_FOLD_TURKISH requires ICU4J. "
+ "Did you forget to include it on your classpath?");
error.initCause(e);
throw error;
}
}
},

/**
* ASCII case folding for simple case insensitive paths.
*/
Expand Down Expand Up @@ -133,7 +151,13 @@ public static String normalize(String string, Iterable<PathNormalization> normal
public static Pattern compilePattern(String regex, Iterable<PathNormalization> normalizations) {
int flags = 0;
for (PathNormalization normalization : normalizations) {
flags |= normalization.patternFlags();
int normalizationFlags = normalization.patternFlags();
if (normalizationFlags != -1) {
flags |= normalizationFlags;
} else {
throw new UnsupportedOperationException(
"Path normalization does not support regular expressions");
}
}
return Pattern.compile(regex, flags);
}
Expand Down
11 changes: 11 additions & 0 deletions jimfs/src/test/java/com/google/common/jimfs/ConfigurationTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package com.google.common.jimfs;

import static com.google.common.jimfs.PathNormalization.CASE_FOLD_ASCII;
import static com.google.common.jimfs.PathNormalization.CASE_FOLD_TURKISH;
import static com.google.common.jimfs.PathNormalization.CASE_FOLD_UNICODE;
import static com.google.common.jimfs.PathNormalization.NFC;
import static com.google.common.jimfs.PathNormalization.NFD;
Expand Down Expand Up @@ -335,4 +336,14 @@ public void testCreateFileSystemFromConfigurationWithWorkingDirectoryNotUnderCon
} catch (IllegalArgumentException expected) {
}
}

@Test
public void testTurkishNormalization() {
Configuration config =
Configuration.windows()
.toBuilder()
.setNameCanonicalNormalization(CASE_FOLD_TURKISH)
.build();
assertThat(config.nameCanonicalNormalization).containsExactly(CASE_FOLD_TURKISH);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Copyright 2013 Google 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.google.common.jimfs;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.FileSystem;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

/**
* Tests a Turkish case-insensitive filesystem using public Files APIs.
*
* @author Ben Hamilton
*/
@RunWith(JUnit4.class)
public class JimfsTurkishCaseInsensitiveFileSystemTest extends AbstractJimfsIntegrationTest {

private static final Configuration TURKISH_CONFIGURATION =
Configuration.windows()
.toBuilder()
.setNameCanonicalNormalization(PathNormalization.CASE_FOLD_TURKISH)
.build();

@Override
protected FileSystem createFileSystem() {
return Jimfs.newFileSystem(TURKISH_CONFIGURATION);
}

@Test
public void caseInsensitiveTurkishMatching() throws IOException {
Files.createDirectory(path("Windows"));
assertThatPath("Windows").isSameFileAs("W\u0130NDOWS");
assertThatPath("Windows").isNotSameFileAs("WINDOWS");
Files.createFile(path("SYSTEM.INI"));
assertThatPath("SYSTEM.INI").isNotSameFileAs("system.ini");
assertThatPath("SYSTEM.INI").isSameFileAs("system.\u0131n\u0131");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package com.google.common.jimfs;

import static com.google.common.jimfs.PathNormalization.CASE_FOLD_ASCII;
import static com.google.common.jimfs.PathNormalization.CASE_FOLD_TURKISH;
import static com.google.common.jimfs.PathNormalization.CASE_FOLD_UNICODE;
import static com.google.common.jimfs.PathNormalization.NFC;
import static com.google.common.jimfs.PathNormalization.NFD;
Expand All @@ -27,7 +28,9 @@

import com.google.common.collect.ImmutableSet;

import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

Expand All @@ -43,6 +46,9 @@ public class PathNormalizationTest {

private ImmutableSet<PathNormalization> normalizations;

@Rule
public ExpectedException thrown = ExpectedException.none();

@Test
public void testNone() {
normalizations = ImmutableSet.of();
Expand Down Expand Up @@ -305,6 +311,29 @@ public void testNormalizeNfdCaseFoldAscii_pattern() {
assertNormalizedPatternMatches("AM\u00c9LIE", "AME\u0301LIE");
}

@Test
public void testCaseFoldTurkish() {
normalizations = ImmutableSet.of(CASE_FOLD_TURKISH);
assertNormalizedEqual("hello", "HELLO");
assertNormalizedEqual("istanbul", "\u0130stanbul");
assertNormalizedUnequal("istanbul", "ISTANBUL");
assertNormalizedEqual("Y\u0131ld\u0131r\u0131m", "YILDIRIM");
assertNormalizedUnequal("Y\u0131ld\u0131r\u0131m", "Yildirim");

// My favorites!
assertNormalizedEqual("c:\\windows", "C:\\W\u0130NDOWS");
assertNormalizedUnequal("c:\\windows", "C:\\WINDOWS");
assertNormalizedEqual(".git", ".G\u0130T");
assertNormalizedUnequal(".git", ".GIT");
}

@Test
public void testCaseFoldTurkishPatternThrows() {
thrown.expectMessage("Path normalization does not support regular expressions");
normalizations = ImmutableSet.of(CASE_FOLD_TURKISH);
PathNormalization.compilePattern("hello", normalizations);
}

/**
* Asserts that the given strings normalize to the same string using the current normalizer.
*/
Expand Down

0 comments on commit a68159d

Please sign in to comment.