Skip to content

Commit

Permalink
[Core] Rewrite # language: tl to # language: te
Browse files Browse the repository at this point in the history
With cucumber/common#1238 the iso code of Telugu was fixed from `tl` to `te`.
To ensure this does not break Cucumber-JVM until it has gone through a
deprecation cycle we rewrite ``# language: tl` to `# language: te` and warn
about the deprecation.
  • Loading branch information
mpkorstanje committed Feb 14, 2021
1 parent 5c19bf4 commit ab27641
Show file tree
Hide file tree
Showing 6 changed files with 137 additions and 50 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.cucumber.core.feature;

import io.cucumber.core.exception.CucumberException;
import io.cucumber.core.resource.Resource;

import java.io.BufferedReader;
Expand All @@ -13,17 +14,18 @@
import static java.util.Locale.ROOT;

/**
* Utilities for reading the encoding of a file.
* Parser for the {@code # encoding: <encoding> } header. Will reload the file
* in the specified encoding if not UTF-8.
*/
final class Encoding {
final class EncodingParser {

private static final Pattern COMMENT_OR_EMPTY_LINE_PATTERN = Pattern.compile("^\\s*#|^\\s*$");
private static final Pattern ENCODING_PATTERN = Pattern.compile("^\\s*#\\s*encoding\\s*:\\s*([0-9a-zA-Z\\-]+)",
Pattern.CASE_INSENSITIVE);
private static final String DEFAULT_ENCODING = UTF_8.name();
private static final String UTF_8_BOM = "\uFEFF";

static String readFile(Resource resource) throws RuntimeException, IOException {
String parse(Resource resource) {
String source = read(resource, DEFAULT_ENCODING);
// Remove UTF8 BOM encoded in first bytes
if (source.startsWith(UTF_8_BOM)) {
Expand All @@ -36,7 +38,7 @@ static String readFile(Resource resource) throws RuntimeException, IOException {
return source;
}

private static String read(Resource resource, String encoding) throws IOException {
private static String read(Resource resource, String encoding) {
char[] buffer = new char[2 * 1024];
final StringBuilder out = new StringBuilder();
try (
Expand All @@ -47,6 +49,8 @@ private static String read(Resource resource, String encoding) throws IOExceptio
while ((read = reader.read(buffer, 0, buffer.length)) > 0) {
out.append(buffer, 0, read);
}
} catch (IOException e) {
throw new CucumberException("Failed to read resource:" + resource.getUri(), e);
}
return out.toString();
}
Expand Down
18 changes: 7 additions & 11 deletions core/src/main/java/io/cucumber/core/feature/FeatureParser.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
package io.cucumber.core.feature;

import io.cucumber.core.exception.CucumberException;
import io.cucumber.core.gherkin.Feature;
import io.cucumber.core.resource.Resource;

import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
Expand All @@ -21,6 +19,9 @@

public final class FeatureParser {

private final EncodingParser encodingParser = new EncodingParser();
private final LanguageParser languageParser = new LanguageParser();

private final Supplier<UUID> idGenerator;

public FeatureParser(Supplier<UUID> idGenerator) {
Expand All @@ -30,7 +31,10 @@ public FeatureParser(Supplier<UUID> idGenerator) {
public Optional<Feature> parseResource(Resource resource) {
requireNonNull(resource);
URI uri = resource.getUri();
String source = read(resource);

String encodingParsed = encodingParser.parse(resource);
String source = languageParser.parse(encodingParsed);

ServiceLoader<io.cucumber.core.gherkin.FeatureParser> services = ServiceLoader
.load(io.cucumber.core.gherkin.FeatureParser.class);
Iterator<io.cucumber.core.gherkin.FeatureParser> iterator = services.iterator();
Expand All @@ -43,12 +47,4 @@ public Optional<Feature> parseResource(Resource resource) {
return Collections.max(parser, version).parse(uri, source, idGenerator);
}

private static String read(Resource resource) {
try {
return Encoding.readFile(resource);
} catch (IOException e) {
throw new CucumberException("Failed to read resource:" + resource.getUri(), e);
}
}

}
26 changes: 26 additions & 0 deletions core/src/main/java/io/cucumber/core/feature/LanguageParser.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package io.cucumber.core.feature;

import io.cucumber.core.logging.Logger;
import io.cucumber.core.logging.LoggerFactory;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
* Parser for the {@code # language: <iso-code> } header. Replaces changed ISO
* codes for backwards compatibility.
*/
class LanguageParser {
private static final Logger log = LoggerFactory.getLogger(FeatureParser.class);
private static final Pattern LANGUAGE_PATTERN = Pattern.compile("^(\\s*#\\s*language\\s*:\\s*)tl");

String parse(String feature) {
Matcher matcher = LANGUAGE_PATTERN.matcher(feature);
if (matcher.find()) {
log.warn(
() -> "The ISO 639-1 code for Telugu was changed from tl to te. Please use '# language: te' in your feature files.");
return matcher.replaceFirst("$1te");
}
return feature;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package io.cucumber.core.feature;

import io.cucumber.core.resource.Resource;
import org.junit.jupiter.api.Test;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;

import static org.junit.jupiter.api.Assertions.assertFalse;

class EncodingParserTest {

private final EncodingParser parser = new EncodingParser();

@Test
void test_utf8_bom_encode() throws RuntimeException, IOException {
Resource resource = resource("src/test/resources/io/cucumber/core/feature/UTF_8_BOM_Encoded.feature");
assertFalse(parser.parse(resource).startsWith("\uFEFF"), "UTF-8 BOM encoding not removed.");
}

@Test
void test_utf8_encode() throws RuntimeException, IOException {
Resource resource = resource("src/test/resources/io/cucumber/core/feature/UTF_8_Encoded.feature");
assertFalse(parser.parse(resource).startsWith("\uFEFF"), "UTF-8 BOM encoding should not be present.");
}

private Resource resource(String name) {
Resource resource = new Resource() {
@Override
public URI getUri() {
return null;
}

@Override
public InputStream getInputStream() throws IOException {

return new FileInputStream(name);
}
};
return resource;
}
}
35 changes: 0 additions & 35 deletions core/src/test/java/io/cucumber/core/feature/EncodingTest.java

This file was deleted.

52 changes: 52 additions & 0 deletions core/src/test/java/io/cucumber/core/feature/FeatureParserTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package io.cucumber.core.feature;

import io.cucumber.core.gherkin.Feature;
import io.cucumber.core.resource.Resource;
import org.hamcrest.CoreMatchers;
import org.hamcrest.MatcherAssert;
import org.junit.jupiter.api.Test;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.Optional;
import java.util.UUID;

import static java.nio.charset.StandardCharsets.UTF_8;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.collection.IsEmptyIterable.emptyIterable;
import static org.junit.jupiter.api.Assertions.*;

class FeatureParserTest {

FeatureParser featureParser = new FeatureParser(UUID::randomUUID);

@Test
void renamesDeprecatedTeToTl() {
Feature feature = featureParser.parseResource(resource("" +
"# language: tl\n" +
"గుణము: Test feature\n" +
" ఉదాహరణ: Test scenario\n" +
" చెప్పబడినది some text\n")).get();
assertThat(feature.getPickles().get(0).getLanguage(), is("te"));
}

private Resource resource(String feature) {
return new Resource() {
@Override
public URI getUri() {
return URI.create("file:test.feature");
}

@Override
public InputStream getInputStream() {
return new ByteArrayInputStream(feature.getBytes(UTF_8));
}
};
}

}

0 comments on commit ab27641

Please sign in to comment.