package aQute.lib.utf8properties;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.Properties;
import aQute.lib.io.IO;
import aQute.libg.reporter.ReporterAdapter;
import aQute.service.reporter.Report.Location;
import junit.framework.TestCase;
/**
* Test if we properly can read
*
* @author aqute
*/
public class UTF8PropertiesTest extends TestCase {
public void testMissingDelimeterAfterQuotedString() throws IOException {
assertError("-foo: bar='abc' ' ' ;", "-foo", 0,
"Found a quote ''' while expecting a delimeter. You should quote the whole values, you can use both single and double quotes:");
assertError("-foo: bar='abc', baz='def' goo='hji'", "-foo", 0,
"Expected a delimeter, like comma or semicolon, after a quoted string but found 'g':");
assertError("-foo: bar='abc' , baz='def'", "-foo", 0);
assertError("-foo: bar='abc' ;", "-foo", 0);
assertError("-foo: bar='\\'abc\\' foo' ;", "-foo", 0);
assertError("-foo: bar=\"\\\"abc\\\" foo\" ;", "-foo", 0);
assertError("foo: bar='abc' ' ' ;", "foo", 0);
assertError("foo: abc \" \" ' '", "foo", 0);
}
String trickypart = "\u00A0\u00A1\u00A2\u00A3\u00A4\u00A5\u00A6\u00A7\u00A8\u00A9\u00AA\u00AB\u00AC\u00AD\u00AE\u00AF"
+ "\u00B0\u00B1\u00B2\u00B3\u00B4\u00B5\u00B6\u00B7\u00B8\u00B9\u00BA\u00BB\u00BC\u00BD\u00BE\u00BF"
+ "\u00C0\u00C1\u00C2\u00C3\u00C4\u00C5\u00C6\u00C7\u00C8\u00C9\u00CA\u00CB\u00CC\u00CD\u00CE\u00CF"
+ "\u00D0\u00D1\u00D2\u00D3\u00D4\u00D5\u00D6\u00D7\u00D8\u00D9\u00DA\u00DB\u00DC\u00DD\u00DE\u00DF"
+ "\u00E0\u00E1\u00E2\u00E3\u00E4\u00E5\u00E6\u00E7\u00E8\u00E9\u00EA\u00EB\u00EC\u00ED\u00EE\u00EF"
+ "\u00F0\u00F1\u00F2\u00F3\u00F4\u00F5\u00F6\u00F7\u00F8\u00F9\u00FA\u00FB\u00FC\u00FD\u00FE\u00FF";
/*
* Entries are generally expected to be a single line of the form, one of
* the following: propertyName=propertyValue propertyName:propertyValue}
*/
public void testSpecificationAssignment() throws IOException {
testProperty("propertyName=propertyValue\n", "propertyName", "propertyValue");
testProperty("propertyName:propertyValue\n", "propertyName", "propertyValue");
testProperty("propertyName propertyValue\n", "propertyName", "propertyValue");
}
/*
* White space that appears between the property name and property value is
* ignored, so the following are equivalent.
*/
public void testSpecificationValueSpaces() throws IOException {
testProperty("name=Stephen\n", "name", "Stephen");
testProperty("name = Stephen\n", "name", "Stephen");
testProperty("name=Stephen", "name", "Stephen");
testProperty("name = Stephen", "name", "Stephen");
}
/*
* White space at the beginning of the line is also ignored.
*/
public void testSpecificationKeySpaces() throws IOException {
testProperty(" name = Stephen\n", "name", "Stephen");
testProperty(" name = Stephen", "name", "Stephen");
}
/*
* Lines that start with the comment characters ! or # are ignored. Blank
* lines are also ignored.
*/
public void testSpecificationComments() throws IOException {
testProperty("\n\n# comment\n!comment\n\nfoo=bar", "foo", "bar");
testProperty("foo=bar\n# comment", "foo", "bar");
testProperty("foo=bar\n! comment", "foo", "bar");
testProperty("# comment\nfoo=bar\n# comment", "foo", "bar");
testProperty("! comment\nfoo=bar\n! comment", "foo", "bar");
testProperty("# comment\nfoo=bar\n# comment\n", "foo", "bar");
testProperty("! comment\nfoo=bar\n! comment\n", "foo", "bar");
}
/*
* Lines that start with the comment characters ! or # are ignored. Blank
* lines are also ignored. Comments which end with \ must not continue to
* next line.
*/
public void testSpecificationCommentContinuation() throws IOException {
testProperty("\n\n# comment\\\n!comment\\\n\nfoo=bar", "foo", "bar");
testProperty("foo=bar\n# comment\\", "foo", "bar");
testProperty("foo=bar\n! comment\\", "foo", "bar");
testProperty("# comment\\\nfoo=bar\n# comment\\", "foo", "bar");
testProperty("! comment\\\nfoo=bar\n! comment\\", "foo", "bar");
testProperty("# comment\\\nfoo=bar\n# comment\\\n", "foo", "bar");
testProperty("! comment\\\nfoo=bar\n! comment\\\n", "foo", "bar");
}
/*
* The property value is generally terminated by the end of the line. White
* space following the property value is not ignored, and is treated as part
* of the property value.
*/
public void testSpecificationWhitespaceValue() throws IOException {
testProperty("foo=bar ", "foo", "bar ");
testProperty("foo=bar \n", "foo", "bar ");
}
/*
* A property value can span several lines if each line is terminated by a
* backslash (‘\’) character. For example:
*/
public void testSpecificationContinutation() throws IOException {
testProperty("targetCities=\\\n" //
+ " Detroit,\\\n" //
+ " Chicago,\\\n" //
+ " Los Angeles\n", "targetCities", "Detroit,Chicago,Los Angeles");
}
/*
* The characters newline, carriage return, and tab can be inserted with
* characters \n, \r, and \t, respectively.
*/
public void testSpecificationControlCharacters() throws IOException {
testProperty("control= \\t\\n\\r\n", "control", "\t\n\r");
}
/*
* The backslash character must be escaped as a double backslash. For
* example:
*/
public void testSpecificationBackslashes() throws IOException {
testProperty("path=c:\\\\docs\\\\doc1", "path", "c:\\docs\\doc1");
}
/*
* UNICODE characters can be entered as they are in a Java program, using
* the \\u prefix. For example, \u002c.
*/
public void testSpecificationUnicode() throws IOException {
testProperty("unicode=\\u002c\n", "unicode", ",");
testProperty("unicode=\\uFEF0\n", "unicode", "\uFEF0");
}
/*
* You can have control characters in keys
*/
public void testControlCharactersInKeys() throws IOException {
testProperty("key\\ key = value\n", "key key", "value", "Found |Invalid");
testProperty("key\\u002Ckey = value\n", "key,key", "value", "Found |Invalid");
testProperty("key\\:key = value\n", "key:key", "value", "Found |Invalid");
}
public void testEmptyContinuations() throws IOException {
testProperty("-plugin: \\\n\\\n\\\nabc", "-plugin", "abc");
testProperty("-plugin: \\\n\\\n\\\nabc\n", "-plugin", "abc");
testProperty("-plugin: \\\n\\\n\\\n abc\n", "-plugin", "abc");
testProperty("-plugin: \\\n \\\n \\\n abc\n", "-plugin", "abc");
}
public void testEmptyKey() throws IOException {
UTF8Properties p = new UTF8Properties();
ReporterAdapter ra = new ReporterAdapter();
p.load(" -runvm: \n" //
+ "#\"-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=1044\"", null, ra);
assertEquals("", p.get("-runvm"));
assertEquals(1, p.size());
}
public void testEmptySpace() throws IOException {
UTF8Properties p = new UTF8Properties();
ReporterAdapter ra = new ReporterAdapter();
p.load("version 1.1\n ", null, ra);
assertEquals("1.1", p.get("version"));
assertEquals(1, p.size());
}
public void testNewlineCr() throws IOException {
UTF8Properties p = new UTF8Properties();
ReporterAdapter ra = new ReporterAdapter();
p.load("a=2\n\rb=3\n\r", null, ra);
assertEquals("2", p.get("a"));
assertEquals("3", p.get("b"));
assertEquals(2, p.size());
}
public void testEscapedNewlinEmpty() throws IOException {
UTF8Properties p = new UTF8Properties();
ReporterAdapter ra = new ReporterAdapter();
p.load("a=x\\\n\n", null, ra);
assertEquals("x", p.get("a"));
assertEquals(1, p.size());
}
public void testPackageinfo() throws IOException {
UTF8Properties p = new UTF8Properties();
ReporterAdapter ra = new ReporterAdapter();
p.load("version 1.0.1", null, ra);
assertEquals("1.0.1", p.get("version"));
assertEquals(1, p.size());
}
public void testPackageinfoWithCrLf() throws IOException {
UTF8Properties p = new UTF8Properties();
ReporterAdapter ra = new ReporterAdapter();
p.load("version 1.0.1\r\n", null, ra);
assertEquals("1.0.1", p.get("version"));
assertEquals(1, p.size());
}
public void testErrorsInParsing() throws IOException {
assertError("\n\n\n\n\n\n\n" //
+ "a;b=9", "a;b", 7, "Invalid property key: `a;b`:");
assertError("\n" //
+ "a=\\ \n a;v=4", "a", 1, "Found \\\\<whitespace>", "Invalid property key: `a;v`");
assertError("\n\n\n\n\n\n\n" //
+ "a", "a", 7, "No value specified for key");
assertError("\npropertyName=property\0Value\n", "propertyName", 1,
"Invalid character in properties: 0 at pos 21:");
assertError("\nproperty\0Name=propertyValue\n", "property?Name", 1,
"Invalid character in properties: 0 at pos 8:");
}
private void assertError(String string, String key, int line, String... check) throws IOException {
ReporterAdapter ra = new ReporterAdapter();
UTF8Properties up = new UTF8Properties();
up.load(string, IO.getFile("foo"), ra);
assertNotNull("No '" + key + "' property found", up.getProperty(key));
if (check.length == 0)
assertEquals(0, ra.getErrors().size());
else {
assertTrue(ra.getErrors().size() > 0);
Location location = ra.getLocation(ra.getErrors().get(0));
assertEquals("Faulty line number", line, location.line);
}
assertTrue(ra.check(check));
}
public void testBackslashEncodingWithReader() throws IOException {
Properties p = new UTF8Properties();
p.load(new StringReader("x=abc \\\\ def\n"));
assertEquals("abc \\ def", p.get("x"));
}
public void testISO8859Encoding() throws IOException {
Properties p = new UTF8Properties();
p.load(new ByteArrayInputStream(("x=" + trickypart + "\n").getBytes("ISO-8859-1")));
assertEquals(trickypart, p.get("x"));
}
public void testUTF8Encoding() throws IOException {
Properties p = new UTF8Properties();
p.load(new ByteArrayInputStream(("x=" + trickypart + "\n").getBytes("UTF-8")));
assertEquals(trickypart, p.get("x"));
}
public void testShowUTF8PropertiesDoNotSkipBackslash() throws IOException {
Properties p = new UTF8Properties();
p.load(new ByteArrayInputStream("x=abc \\ def\n".getBytes("UTF-8")));
assertEquals("abc def", p.get("x"));
}
public void testShowPropertiesSkipBackslash() throws IOException {
Properties p = new Properties();
p.load(new StringReader("x=abc \\ def\n"));
assertEquals("abc def", p.get("x"));
}
public void testContinuation() throws IOException {
Properties p = new Properties();
p.load(new StringReader("x=abc \\\n def\n"));
assertEquals("abc def", p.get("x"));
}
public void testWriteWithoutComment() throws IOException {
UTF8Properties p = new UTF8Properties();
p.put("Foo", "Foo");
ByteArrayOutputStream bout = new ByteArrayOutputStream();
p.store(bout);
String s = new String(bout.toByteArray(), "UTF-8");
assertFalse(s.startsWith("#"));
assertTrue("Foo should be in there", s.indexOf("Foo") >= 0);
}
public void testWrite() throws IOException {
UTF8Properties p = new UTF8Properties();
p.put("Foo", "Foo");
p.put("Bar", "Bar\n#comment");
StringWriter sw = new StringWriter();
p.store(sw, null);
String s = sw.toString();
assertNotNull(s);
assertTrue(s.contains("#comment"));
UTF8Properties p1 = new UTF8Properties();
p1.load(new StringReader(s));
assertEquals(p, p1);
}
private void testProperty(String content, String key, String value) throws IOException {
testProperty(content, key, value, null);
}
private void testProperty(String content, String key, String value, String check) throws IOException {
testProperty0(content, key, value, check);
testProperty0(content.replaceAll("\n", "\r\n"), key, value, check);
testProperty0(content.replaceAll("\n", "\r"), key, value, check);
}
private void testProperty0(String content, String key, String value, String check) throws IOException {
UTF8Properties p = new UTF8Properties();
ReporterAdapter ra = new ReporterAdapter();
p.load(content, null, ra);
if (check == null)
assertTrue(ra.check());
else
assertTrue(ra.check(check));
assertEquals(value, p.get(key));
assertEquals(1, p.size());
Properties pp = new Properties();
pp.load(new StringReader(content));
assertEquals(value, pp.get(key));
assertEquals(1, pp.size());
assertEquals(pp, p);
}
}