diff --git a/src/main/java/org/codejive/properties/Properties.java b/src/main/java/org/codejive/properties/Properties.java
index 38d4fde..28aa0ff 100644
--- a/src/main/java/org/codejive/properties/Properties.java
+++ b/src/main/java/org/codejive/properties/Properties.java
@@ -8,12 +8,12 @@
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.*;
+import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
-import java.util.stream.Stream;
-import java.util.stream.StreamSupport;
+import org.codejive.properties.PropertiesParser.Token;
/**
* This class is a replacement for java.util.Properties, with the difference that it
@@ -134,7 +134,7 @@ public Enumeration propertyNames() {
* value are strings, including the keys in the default property list.
*/
public Set stringPropertyNames() {
- return Collections.unmodifiableSet(flatten().keySet());
+ return Collections.unmodifiableSet(flattened().keySet());
}
/**
@@ -144,7 +144,7 @@ public Set stringPropertyNames() {
*/
public void list(PrintStream out) {
try {
- flatten().store(out);
+ flattened().store(out);
} catch (IOException e) {
// Ignore any errors
}
@@ -157,7 +157,7 @@ public void list(PrintStream out) {
*/
public void list(PrintWriter out) {
try {
- flatten().store(out);
+ flattened().store(out);
} catch (IOException e) {
// Ignore any errors
}
@@ -230,6 +230,7 @@ private void flatten(Properties target) {
@Override
public Set> entrySet() {
+ if (tokens.isEmpty()) return Collections.emptySet();
return new AbstractSet>() {
@Override
public Iterator> iterator() {
@@ -272,6 +273,7 @@ public int size() {
* @return A set of raw key values
*/
public Set rawKeySet() {
+ if (tokens.isEmpty()) return Collections.emptySet();
return tokens.stream()
.filter(t -> t.type == PropertiesParser.Type.KEY)
.map(PropertiesParser.Token::getRaw)
@@ -285,10 +287,10 @@ public Set rawKeySet() {
* @return a collection of raw values.
*/
public Collection rawValues() {
- return combined(tokens)
- .filter(ts -> ts.get(0).type == PropertiesParser.Type.KEY)
- .map(ts -> ts.get(2).getRaw())
- .collect(Collectors.toList());
+ if (tokens.isEmpty()) return Collections.emptyList();
+ List result = new ArrayList<>();
+ walkProperties((key, value) -> result.add(value != null ? value.getRaw() : ""));
+ return result;
}
/**
@@ -298,10 +300,40 @@ public Collection rawValues() {
* @return A set of raw key-value entries
*/
public Set> rawEntrySet() {
- return combined(tokens)
- .filter(ts -> ts.get(0).type == PropertiesParser.Type.KEY)
- .map(ts -> new SimpleEntry<>(ts.get(0).getRaw(), ts.get(2).getRaw()))
- .collect(Collectors.toCollection(LinkedHashSet::new));
+ if (tokens.isEmpty()) return Collections.emptySet();
+ Set> result = new LinkedHashSet<>();
+ walkProperties(
+ (key, value) ->
+ result.add(
+ new SimpleEntry<>(
+ key.getRaw(), value != null ? value.getRaw() : "")));
+ return result;
+ }
+
+ private void walkProperties(BiConsumer func) {
+ if (tokens.isEmpty()) return;
+ Cursor c = Cursor.first(tokens);
+ while (c.hasToken()) {
+ if (c.isType(PropertiesParser.Type.KEY)) {
+ PropertiesParser.Token keyToken = c.token();
+ c.next();
+ if (c.isType(PropertiesParser.Type.SEPARATOR)) {
+ c.next();
+ if (c.isType(PropertiesParser.Type.VALUE)) {
+ func.accept(keyToken, c.token());
+ c.next();
+ } else {
+ // We're dealing with a value-less property
+ func.accept(keyToken, null);
+ }
+ } else {
+ // We're dealing with a key-only property
+ func.accept(keyToken, null);
+ }
+ } else {
+ c.next();
+ }
+ }
}
@Override
@@ -711,9 +743,7 @@ public Properties escaped() {
}
private static List escapeTokens(List tokens) {
- return mapKeyValues(
- tokens,
- ts -> Arrays.asList(escapeToken(ts.get(0)), ts.get(1), escapeToken(ts.get(2))));
+ return mapKeyValues(tokens, Properties::escapeToken, Properties::escapeToken);
}
private static PropertiesParser.Token escapeToken(PropertiesParser.Token token) {
@@ -738,9 +768,7 @@ public Properties unescaped() {
private static List unescapeTokens(
List tokens) {
- return mapKeyValues(
- tokens,
- ts -> Arrays.asList(unescapeToken(ts.get(0)), ts.get(1), unescapeToken(ts.get(2))));
+ return mapKeyValues(tokens, Properties::unescapeToken, Properties::unescapeToken);
}
private static PropertiesParser.Token unescapeToken(PropertiesParser.Token token) {
@@ -753,46 +781,22 @@ private static PropertiesParser.Token unescapeToken(PropertiesParser.Token token
private static List mapKeyValues(
List tokens,
- Function, List> mapper) {
- return combined(tokens)
+ Function keyMapper,
+ Function valueMapper) {
+ return tokens.stream()
.map(
- ts -> {
- if (ts.get(0).type == PropertiesParser.Type.KEY) {
- return mapper.apply(ts);
+ tk -> {
+ if (tk.type == PropertiesParser.Type.KEY) {
+ return keyMapper.apply(tk);
+ } else if (tk.type == PropertiesParser.Type.VALUE) {
+ return valueMapper.apply(tk);
} else {
- return ts;
+ return tk;
}
})
- .flatMap(Collection::stream)
.collect(Collectors.toList());
}
- private static Stream> combined(
- List tokens) {
- Iterator> iter =
- new Iterator>() {
- Iterator i = tokens.iterator();
-
- @Override
- public boolean hasNext() {
- return i.hasNext();
- }
-
- @Override
- public List next() {
- PropertiesParser.Token t = i.next();
- if (t.type == PropertiesParser.Type.KEY) {
- return Arrays.asList(t, i.next(), i.next());
- } else {
- return Collections.singletonList(t);
- }
- }
- };
-
- return StreamSupport.stream(
- Spliterators.spliterator(iter, tokens.size(), Spliterator.SORTED), false);
- }
-
/**
* Copies all entries from the java.util.Properties object to this object
*
@@ -865,10 +869,22 @@ private Properties load(List ts) {
for (PropertiesParser.Token token : tokens) {
if (token.type == PropertiesParser.Type.KEY) {
key = token.getText();
+ }
+ if (token.type == PropertiesParser.Type.SEPARATOR && key == null) {
+ // In case if a name-less property
+ key = "";
} else if (token.type == PropertiesParser.Type.VALUE) {
values.put(key, token.getText());
+ key = null;
+ } else if (token.isEol() && key != null) {
+ // In case of value-less properties
+ values.put(key, "");
}
}
+ // In case of the last property being value-less
+ if (key != null) {
+ values.put(key, "");
+ }
return this;
}
diff --git a/src/main/java/org/codejive/properties/PropertiesParser.java b/src/main/java/org/codejive/properties/PropertiesParser.java
index c43ec85..06174b2 100644
--- a/src/main/java/org/codejive/properties/PropertiesParser.java
+++ b/src/main/java/org/codejive/properties/PropertiesParser.java
@@ -103,7 +103,7 @@ public String getRaw() {
* Returns the token's processed value. Meaning this value will not contain any escape
* sequences but only actual characters.
*
- * @return
+ * @return a string containing the token's processed value
*/
public String getText() {
return text != null ? text : raw;
@@ -115,6 +115,7 @@ public String getText() {
* @return true if whitespace ending in EOL, false otherwise
*/
public boolean isEol() {
+ if (raw.isEmpty()) return false;
int ch = raw.charAt(raw.length() - 1);
return type == Type.WHITESPACE && PropertiesParser.isEol(ch);
}
@@ -125,6 +126,7 @@ public boolean isEol() {
* @return true if whitespace NOT ending in EOL, false otherwise
*/
public boolean isWs() {
+ if (raw.isEmpty()) return false;
int ch = raw.charAt(raw.length() - 1);
return type == Type.WHITESPACE && !PropertiesParser.isEol(ch);
}
diff --git a/src/test/java/org/codejive/properties/TestProperties.java b/src/test/java/org/codejive/properties/TestProperties.java
index 10ad235..1d8ecc2 100644
--- a/src/test/java/org/codejive/properties/TestProperties.java
+++ b/src/test/java/org/codejive/properties/TestProperties.java
@@ -17,13 +17,31 @@ public class TestProperties {
@Test
void testLoad() throws IOException, URISyntaxException {
Properties p = Properties.loadProperties(getResource("/test.properties"));
- assertThat(p).size().isEqualTo(7);
+ assertThat(p).size().isEqualTo(10);
assertThat(p.keySet())
.containsExactly(
- "one", "two", "three", " with spaces", "altsep", "multiline", "key.4");
+ "one",
+ "two",
+ "three",
+ " with spaces",
+ "altsep",
+ "multiline",
+ "novalue",
+ "keyonly",
+ "",
+ "key.4");
assertThat(p.rawKeySet())
.containsExactly(
- "one", "two", "three", "\\ with\\ spaces", "altsep", "multiline", "key.4");
+ "one",
+ "two",
+ "three",
+ "\\ with\\ spaces",
+ "altsep",
+ "multiline",
+ "novalue",
+ "keyonly",
+ "",
+ "key.4");
assertThat(p.values())
.containsExactly(
"simple",
@@ -32,6 +50,9 @@ void testLoad() throws IOException, URISyntaxException {
"everywhere ",
"value",
"one two three",
+ "",
+ "",
+ "",
"\u1234\u1234");
assertThat(p.rawValues())
.containsExactly(
@@ -41,6 +62,9 @@ void testLoad() throws IOException, URISyntaxException {
"everywhere ",
"value",
"one \\\n two \\\n\tthree",
+ "",
+ "",
+ "",
"\\u1234\u1234");
assertThat(p.entrySet())
.containsExactly(
@@ -50,6 +74,9 @@ void testLoad() throws IOException, URISyntaxException {
new AbstractMap.SimpleEntry<>(" with spaces", "everywhere "),
new AbstractMap.SimpleEntry<>("altsep", "value"),
new AbstractMap.SimpleEntry<>("multiline", "one two three"),
+ new AbstractMap.SimpleEntry<>("novalue", ""),
+ new AbstractMap.SimpleEntry<>("keyonly", ""),
+ new AbstractMap.SimpleEntry<>("", ""),
new AbstractMap.SimpleEntry<>("key.4", "\u1234\u1234"));
assertThat(p.rawEntrySet())
.containsExactly(
@@ -59,19 +86,40 @@ void testLoad() throws IOException, URISyntaxException {
new AbstractMap.SimpleEntry<>("\\ with\\ spaces", "everywhere "),
new AbstractMap.SimpleEntry<>("altsep", "value"),
new AbstractMap.SimpleEntry<>("multiline", "one \\\n two \\\n\tthree"),
+ new AbstractMap.SimpleEntry<>("novalue", ""),
+ new AbstractMap.SimpleEntry<>("keyonly", ""),
+ new AbstractMap.SimpleEntry<>("", ""),
new AbstractMap.SimpleEntry<>("key.4", "\\u1234\u1234"));
}
@Test
void testLoadCrLf() throws IOException, URISyntaxException {
Properties p = Properties.loadProperties(getResource("/testcrlf.properties"));
- assertThat(p).size().isEqualTo(7);
+ assertThat(p).size().isEqualTo(10);
assertThat(p.keySet())
.containsExactly(
- "one", "two", "three", " with spaces", "altsep", "multiline", "key.4");
+ "one",
+ "two",
+ "three",
+ " with spaces",
+ "altsep",
+ "multiline",
+ "novalue",
+ "keyonly",
+ "",
+ "key.4");
assertThat(p.rawKeySet())
.containsExactly(
- "one", "two", "three", "\\ with\\ spaces", "altsep", "multiline", "key.4");
+ "one",
+ "two",
+ "three",
+ "\\ with\\ spaces",
+ "altsep",
+ "multiline",
+ "novalue",
+ "keyonly",
+ "",
+ "key.4");
assertThat(p.values())
.containsExactly(
"simple",
@@ -80,6 +128,9 @@ void testLoadCrLf() throws IOException, URISyntaxException {
"everywhere ",
"value",
"one two three",
+ "",
+ "",
+ "",
"\u1234\u1234");
assertThat(p.rawValues())
.containsExactly(
@@ -89,6 +140,9 @@ void testLoadCrLf() throws IOException, URISyntaxException {
"everywhere ",
"value",
"one \\\r\n two \\\r\n\tthree",
+ "",
+ "",
+ "",
"\\u1234\u1234");
assertThat(p.entrySet())
.containsExactly(
@@ -98,6 +152,9 @@ void testLoadCrLf() throws IOException, URISyntaxException {
new AbstractMap.SimpleEntry<>(" with spaces", "everywhere "),
new AbstractMap.SimpleEntry<>("altsep", "value"),
new AbstractMap.SimpleEntry<>("multiline", "one two three"),
+ new AbstractMap.SimpleEntry<>("novalue", ""),
+ new AbstractMap.SimpleEntry<>("keyonly", ""),
+ new AbstractMap.SimpleEntry<>("", ""),
new AbstractMap.SimpleEntry<>("key.4", "\u1234\u1234"));
assertThat(p.rawEntrySet())
.containsExactly(
@@ -108,9 +165,180 @@ void testLoadCrLf() throws IOException, URISyntaxException {
new AbstractMap.SimpleEntry<>("altsep", "value"),
new AbstractMap.SimpleEntry<>(
"multiline", "one \\\r\n two \\\r\n\tthree"),
+ new AbstractMap.SimpleEntry<>("novalue", ""),
+ new AbstractMap.SimpleEntry<>("keyonly", ""),
+ new AbstractMap.SimpleEntry<>("", ""),
new AbstractMap.SimpleEntry<>("key.4", "\\u1234\u1234"));
}
+ @Test
+ void testLoadKeyAtEnd() throws IOException, URISyntaxException {
+ Properties p = Properties.loadProperties(getResource("/test-keyatend.properties"));
+ assertThat(p).size().isEqualTo(11);
+ assertThat(p.keySet())
+ .containsExactly(
+ "one",
+ "two",
+ "three",
+ " with spaces",
+ "altsep",
+ "multiline",
+ "novalue",
+ "keyonly",
+ "",
+ "key.4",
+ "key.at.end");
+ assertThat(p.rawKeySet())
+ .containsExactly(
+ "one",
+ "two",
+ "three",
+ "\\ with\\ spaces",
+ "altsep",
+ "multiline",
+ "novalue",
+ "keyonly",
+ "",
+ "key.4",
+ "key.at.end");
+ assertThat(p.values())
+ .containsExactly(
+ "simple",
+ "value containing spaces",
+ "and escapes\n\t\r\f",
+ "everywhere ",
+ "value",
+ "one two three",
+ "",
+ "",
+ "",
+ "\u1234\u1234",
+ "");
+ assertThat(p.rawValues())
+ .containsExactly(
+ "simple",
+ "value containing spaces",
+ "and escapes\\n\\t\\r\\f",
+ "everywhere ",
+ "value",
+ "one \\\n two \\\n\tthree",
+ "",
+ "",
+ "",
+ "\\u1234\u1234",
+ "");
+ assertThat(p.entrySet())
+ .containsExactly(
+ new AbstractMap.SimpleEntry<>("one", "simple"),
+ new AbstractMap.SimpleEntry<>("two", "value containing spaces"),
+ new AbstractMap.SimpleEntry<>("three", "and escapes\n\t\r\f"),
+ new AbstractMap.SimpleEntry<>(" with spaces", "everywhere "),
+ new AbstractMap.SimpleEntry<>("altsep", "value"),
+ new AbstractMap.SimpleEntry<>("multiline", "one two three"),
+ new AbstractMap.SimpleEntry<>("novalue", ""),
+ new AbstractMap.SimpleEntry<>("keyonly", ""),
+ new AbstractMap.SimpleEntry<>("", ""),
+ new AbstractMap.SimpleEntry<>("key.4", "\u1234\u1234"),
+ new AbstractMap.SimpleEntry<>("key.at.end", ""));
+ assertThat(p.rawEntrySet())
+ .containsExactly(
+ new AbstractMap.SimpleEntry<>("one", "simple"),
+ new AbstractMap.SimpleEntry<>("two", "value containing spaces"),
+ new AbstractMap.SimpleEntry<>("three", "and escapes\\n\\t\\r\\f"),
+ new AbstractMap.SimpleEntry<>("\\ with\\ spaces", "everywhere "),
+ new AbstractMap.SimpleEntry<>("altsep", "value"),
+ new AbstractMap.SimpleEntry<>("multiline", "one \\\n two \\\n\tthree"),
+ new AbstractMap.SimpleEntry<>("novalue", ""),
+ new AbstractMap.SimpleEntry<>("keyonly", ""),
+ new AbstractMap.SimpleEntry<>("", ""),
+ new AbstractMap.SimpleEntry<>("key.4", "\\u1234\u1234"),
+ new AbstractMap.SimpleEntry<>("key.at.end", ""));
+ }
+
+ @Test
+ void testLoadSeparatorAtEnd() throws IOException, URISyntaxException {
+ Properties p = Properties.loadProperties(getResource("/test-separatoratend.properties"));
+ assertThat(p).size().isEqualTo(11);
+ assertThat(p.keySet())
+ .containsExactly(
+ "one",
+ "two",
+ "three",
+ " with spaces",
+ "altsep",
+ "multiline",
+ "novalue",
+ "keyonly",
+ "",
+ "key.4",
+ "separator.at.end");
+ assertThat(p.rawKeySet())
+ .containsExactly(
+ "one",
+ "two",
+ "three",
+ "\\ with\\ spaces",
+ "altsep",
+ "multiline",
+ "novalue",
+ "keyonly",
+ "",
+ "key.4",
+ "separator.at.end");
+ assertThat(p.values())
+ .containsExactly(
+ "simple",
+ "value containing spaces",
+ "and escapes\n\t\r\f",
+ "everywhere ",
+ "value",
+ "one two three",
+ "",
+ "",
+ "",
+ "\u1234\u1234",
+ "");
+ assertThat(p.rawValues())
+ .containsExactly(
+ "simple",
+ "value containing spaces",
+ "and escapes\\n\\t\\r\\f",
+ "everywhere ",
+ "value",
+ "one \\\n two \\\n\tthree",
+ "",
+ "",
+ "",
+ "\\u1234\u1234",
+ "");
+ assertThat(p.entrySet())
+ .containsExactly(
+ new AbstractMap.SimpleEntry<>("one", "simple"),
+ new AbstractMap.SimpleEntry<>("two", "value containing spaces"),
+ new AbstractMap.SimpleEntry<>("three", "and escapes\n\t\r\f"),
+ new AbstractMap.SimpleEntry<>(" with spaces", "everywhere "),
+ new AbstractMap.SimpleEntry<>("altsep", "value"),
+ new AbstractMap.SimpleEntry<>("multiline", "one two three"),
+ new AbstractMap.SimpleEntry<>("novalue", ""),
+ new AbstractMap.SimpleEntry<>("keyonly", ""),
+ new AbstractMap.SimpleEntry<>("", ""),
+ new AbstractMap.SimpleEntry<>("key.4", "\u1234\u1234"),
+ new AbstractMap.SimpleEntry<>("separator.at.end", ""));
+ assertThat(p.rawEntrySet())
+ .containsExactly(
+ new AbstractMap.SimpleEntry<>("one", "simple"),
+ new AbstractMap.SimpleEntry<>("two", "value containing spaces"),
+ new AbstractMap.SimpleEntry<>("three", "and escapes\\n\\t\\r\\f"),
+ new AbstractMap.SimpleEntry<>("\\ with\\ spaces", "everywhere "),
+ new AbstractMap.SimpleEntry<>("altsep", "value"),
+ new AbstractMap.SimpleEntry<>("multiline", "one \\\n two \\\n\tthree"),
+ new AbstractMap.SimpleEntry<>("novalue", ""),
+ new AbstractMap.SimpleEntry<>("keyonly", ""),
+ new AbstractMap.SimpleEntry<>("", ""),
+ new AbstractMap.SimpleEntry<>("key.4", "\\u1234\u1234"),
+ new AbstractMap.SimpleEntry<>("separator.at.end", ""));
+ }
+
@Test
void testStore() throws IOException, URISyntaxException {
Path f = getResource("/test.properties");
@@ -201,7 +429,7 @@ void testGetProperty() throws IOException, URISyntaxException {
p.setProperty("five", "5", "a new comment");
assertThat(p).size().isEqualTo(3);
assertThat(p.keySet()).containsExactly("two", "altsep", "five");
- assertThat(p.stringPropertyNames()).size().isEqualTo(8);
+ assertThat(p.stringPropertyNames()).size().isEqualTo(11);
assertThat(p.stringPropertyNames())
.containsExactly(
"one",
@@ -210,6 +438,9 @@ void testGetProperty() throws IOException, URISyntaxException {
" with spaces",
"altsep",
"multiline",
+ "novalue",
+ "keyonly",
+ "",
"key.4",
"five");
assertThat(p.getProperty("one")).isEqualTo("simple");
@@ -222,6 +453,9 @@ void testGetProperty() throws IOException, URISyntaxException {
assertThat(p.getProperty(" with spaces")).isEqualTo("everywhere ");
assertThat(p.getProperty("altsep")).isEqualTo("");
assertThat(p.getProperty("multiline")).isEqualTo("one two three");
+ assertThat(p.getProperty("novalue")).isEmpty();
+ assertThat(p.getProperty("keyonly")).isEmpty();
+ assertThat(p.getProperty("")).isEmpty();
assertThat(p.getProperty("key.4")).isEqualTo("\u1234\u1234");
assertThat(p.getProperty("five")).isEqualTo("5");
assertThat(p.getPropertyComment("five")).containsExactly("# a new comment");
@@ -318,14 +552,35 @@ void testPut() throws IOException, URISyntaxException {
p.put(" with spaces", "everywhere ");
p.put("altsep", "value");
p.put("multiline", "one two three");
+ p.put("novalue", "");
+ p.put("keyonly", "");
+ p.put("", "");
p.put("key.4", "\u1234\u1234");
- assertThat(p).size().isEqualTo(7);
+ assertThat(p).size().isEqualTo(10);
assertThat(p.keySet())
.containsExactly(
- "one", "two", "three", " with spaces", "altsep", "multiline", "key.4");
+ "one",
+ "two",
+ "three",
+ " with spaces",
+ "altsep",
+ "multiline",
+ "novalue",
+ "keyonly",
+ "",
+ "key.4");
assertThat(p.rawKeySet())
.containsExactly(
- "one", "two", "three", "\\ with\\ spaces", "altsep", "multiline", "key.4");
+ "one",
+ "two",
+ "three",
+ "\\ with\\ spaces",
+ "altsep",
+ "multiline",
+ "novalue",
+ "keyonly",
+ "",
+ "key.4");
assertThat(p.values())
.containsExactly(
"simple",
@@ -334,6 +589,9 @@ void testPut() throws IOException, URISyntaxException {
"everywhere ",
"value",
"one two three",
+ "",
+ "",
+ "",
"\u1234\u1234");
assertThat(p.rawValues())
.containsExactly(
@@ -343,6 +601,9 @@ void testPut() throws IOException, URISyntaxException {
"everywhere ",
"value",
"one two three",
+ "",
+ "",
+ "",
"\u1234\u1234");
assertThat(p.entrySet())
.containsExactly(
@@ -352,6 +613,9 @@ void testPut() throws IOException, URISyntaxException {
new AbstractMap.SimpleEntry<>(" with spaces", "everywhere "),
new AbstractMap.SimpleEntry<>("altsep", "value"),
new AbstractMap.SimpleEntry<>("multiline", "one two three"),
+ new AbstractMap.SimpleEntry<>("novalue", ""),
+ new AbstractMap.SimpleEntry<>("keyonly", ""),
+ new AbstractMap.SimpleEntry<>("", ""),
new AbstractMap.SimpleEntry<>("key.4", "\u1234\u1234"));
assertThat(p.rawEntrySet())
.containsExactly(
@@ -361,6 +625,9 @@ void testPut() throws IOException, URISyntaxException {
new AbstractMap.SimpleEntry<>("\\ with\\ spaces", "everywhere "),
new AbstractMap.SimpleEntry<>("altsep", "value"),
new AbstractMap.SimpleEntry<>("multiline", "one two three"),
+ new AbstractMap.SimpleEntry<>("novalue", ""),
+ new AbstractMap.SimpleEntry<>("keyonly", ""),
+ new AbstractMap.SimpleEntry<>("", ""),
new AbstractMap.SimpleEntry<>("key.4", "\u1234\u1234"));
StringWriter sw = new StringWriter();
p.store(sw);
@@ -377,6 +644,9 @@ void testSetProperty() throws IOException, URISyntaxException {
p.setProperty(" with spaces", "everywhere ");
p.setProperty("altsep", "value");
p.setProperty("multiline", "one two three");
+ p.put("novalue", "");
+ p.put("keyonly", "");
+ p.put("", "");
p.setProperty("key.4", "\u1234\u1234");
StringWriter sw = new StringWriter();
p.store(sw);
@@ -392,14 +662,35 @@ void testPutRaw() throws IOException, URISyntaxException {
p.putRaw("\\ with\\ spaces", "everywhere ");
p.putRaw("altsep", "value");
p.putRaw("multiline", "one \\\n two \\\n\tthree");
+ p.putRaw("novalue", "");
+ p.putRaw("keyonly", "");
+ p.putRaw("", "");
p.putRaw("key.4", "\\u1234\u1234");
- assertThat(p).size().isEqualTo(7);
+ assertThat(p).size().isEqualTo(10);
assertThat(p.keySet())
.containsExactly(
- "one", "two", "three", " with spaces", "altsep", "multiline", "key.4");
+ "one",
+ "two",
+ "three",
+ " with spaces",
+ "altsep",
+ "multiline",
+ "novalue",
+ "keyonly",
+ "",
+ "key.4");
assertThat(p.rawKeySet())
.containsExactly(
- "one", "two", "three", "\\ with\\ spaces", "altsep", "multiline", "key.4");
+ "one",
+ "two",
+ "three",
+ "\\ with\\ spaces",
+ "altsep",
+ "multiline",
+ "novalue",
+ "keyonly",
+ "",
+ "key.4");
assertThat(p.values())
.containsExactly(
"simple",
@@ -408,6 +699,9 @@ void testPutRaw() throws IOException, URISyntaxException {
"everywhere ",
"value",
"one two three",
+ "",
+ "",
+ "",
"\u1234\u1234");
assertThat(p.rawValues())
.containsExactly(
@@ -417,6 +711,9 @@ void testPutRaw() throws IOException, URISyntaxException {
"everywhere ",
"value",
"one \\\n two \\\n\tthree",
+ "",
+ "",
+ "",
"\\u1234\u1234");
assertThat(p.entrySet())
.containsExactly(
@@ -426,6 +723,9 @@ void testPutRaw() throws IOException, URISyntaxException {
new AbstractMap.SimpleEntry<>(" with spaces", "everywhere "),
new AbstractMap.SimpleEntry<>("altsep", "value"),
new AbstractMap.SimpleEntry<>("multiline", "one two three"),
+ new AbstractMap.SimpleEntry<>("novalue", ""),
+ new AbstractMap.SimpleEntry<>("keyonly", ""),
+ new AbstractMap.SimpleEntry<>("", ""),
new AbstractMap.SimpleEntry<>("key.4", "\u1234\u1234"));
assertThat(p.rawEntrySet())
.containsExactly(
@@ -435,6 +735,9 @@ void testPutRaw() throws IOException, URISyntaxException {
new AbstractMap.SimpleEntry<>("\\ with\\ spaces", "everywhere "),
new AbstractMap.SimpleEntry<>("altsep", "value"),
new AbstractMap.SimpleEntry<>("multiline", "one \\\n two \\\n\tthree"),
+ new AbstractMap.SimpleEntry<>("novalue", ""),
+ new AbstractMap.SimpleEntry<>("keyonly", ""),
+ new AbstractMap.SimpleEntry<>("", ""),
new AbstractMap.SimpleEntry<>("key.4", "\\u1234\u1234"));
StringWriter sw = new StringWriter();
p.store(sw);
@@ -615,6 +918,9 @@ void testRemoveAll() throws IOException, URISyntaxException {
p.remove(" with spaces");
p.remove("altsep");
p.remove("multiline");
+ p.remove("novalue");
+ p.remove("keyonly");
+ p.remove("");
p.remove("key.4");
StringWriter sw = new StringWriter();
p.store(sw);
@@ -630,7 +936,7 @@ void testRemoveNonExistent() throws IOException, URISyntaxException {
@Test
void testRemoveMiddleIterator() throws IOException, URISyntaxException {
Properties p = Properties.loadProperties(getResource("/test.properties"));
- Iterator iter = p.keySet().iterator();
+ Iterator iter = p.keySet().iterator();
while (iter.hasNext()) {
if (iter.next().equals("three")) {
iter.remove();
@@ -667,10 +973,19 @@ public void testInteropLoad() throws IOException, URISyntaxException {
try (Reader br = Files.newBufferedReader(getResource("/test.properties"))) {
p.load(br);
}
- assertThat(p).size().isEqualTo(7);
+ assertThat(p).size().isEqualTo(10);
assertThat(p.keySet())
.containsExactlyInAnyOrder(
- "one", "two", "three", " with spaces", "altsep", "multiline", "key.4");
+ "one",
+ "two",
+ "three",
+ " with spaces",
+ "altsep",
+ "multiline",
+ "novalue",
+ "keyonly",
+ "",
+ "key.4");
assertThat(p.values())
.containsExactlyInAnyOrder(
"simple",
@@ -679,6 +994,9 @@ public void testInteropLoad() throws IOException, URISyntaxException {
"everywhere ",
"value",
"one two three",
+ "",
+ "",
+ "",
"\u1234\u1234");
}
@@ -707,6 +1025,9 @@ void testInteropPutLoad() throws IOException, URISyntaxException {
p.put(" with spaces", "everywhere ");
p.put("altsep", "value");
p.put("multiline", "one two three");
+ p.put("novalue", "");
+ p.put("keyonly", "");
+ p.put("", "");
p.put("key.4", "\u1234");
StringWriter sw = new StringWriter();
p.store(sw, null);
@@ -721,10 +1042,19 @@ void testInteropPutLoad() throws IOException, URISyntaxException {
assertThat(sw.toString()).contains("key.4=\u1234" + System.lineSeparator());
java.util.Properties p2 = new java.util.Properties();
p2.load(new StringReader(sw.toString()));
- assertThat(p2).size().isEqualTo(7);
+ assertThat(p2).size().isEqualTo(10);
assertThat(p2.keySet())
.containsExactlyInAnyOrder(
- "one", "two", "three", " with spaces", "altsep", "multiline", "key.4");
+ "one",
+ "two",
+ "three",
+ " with spaces",
+ "altsep",
+ "multiline",
+ "novalue",
+ "keyonly",
+ "",
+ "key.4");
assertThat(p2.values())
.containsExactlyInAnyOrder(
"simple",
@@ -733,6 +1063,9 @@ void testInteropPutLoad() throws IOException, URISyntaxException {
"everywhere ",
"value",
"one two three",
+ "",
+ "",
+ "",
"\u1234");
}
diff --git a/src/test/resources/test-comment.properties b/src/test/resources/test-comment.properties
index a181da2..cf24f6e 100644
--- a/src/test/resources/test-comment.properties
+++ b/src/test/resources/test-comment.properties
@@ -13,4 +13,7 @@ altsep:value
multiline = one \
two \
three
+novalue=
+keyonly
+=
key.4 = \u1234ሴ
diff --git a/src/test/resources/test-escaped.properties b/src/test/resources/test-escaped.properties
index dc8d068..843f915 100644
--- a/src/test/resources/test-escaped.properties
+++ b/src/test/resources/test-escaped.properties
@@ -13,4 +13,7 @@ altsep:value
multiline = one \
two \
three
+novalue=
+keyonly
+=
key.4 = \u1234\u1234
diff --git a/src/test/resources/test-getproperty.properties b/src/test/resources/test-getproperty.properties
index 146224a..3a86258 100644
--- a/src/test/resources/test-getproperty.properties
+++ b/src/test/resources/test-getproperty.properties
@@ -4,5 +4,8 @@ three=and escapes\n\t\r\f
\ with\ spaces=everywhere
altsep=
multiline=one two three
+novalue=
+keyonly=
+=
key.4=ሴሴ
five=5
\ No newline at end of file
diff --git a/src/test/resources/test-keyatend-putnew.properties b/src/test/resources/test-keyatend-putnew.properties
index 5ee5f32..d986472 100644
--- a/src/test/resources/test-keyatend-putnew.properties
+++ b/src/test/resources/test-keyatend-putnew.properties
@@ -13,6 +13,9 @@ altsep:value
multiline = one \
two \
three
+novalue=
+keyonly
+=
key.4 = \u1234ሴ
key.at.end
five=5
\ No newline at end of file
diff --git a/src/test/resources/test-keyatend.properties b/src/test/resources/test-keyatend.properties
index f67dc9a..1a2426b 100644
--- a/src/test/resources/test-keyatend.properties
+++ b/src/test/resources/test-keyatend.properties
@@ -13,5 +13,8 @@ altsep:value
multiline = one \
two \
three
+novalue=
+keyonly
+=
key.4 = \u1234ሴ
key.at.end
\ No newline at end of file
diff --git a/src/test/resources/test-put.properties b/src/test/resources/test-put.properties
index 17e673a..da7d93c 100644
--- a/src/test/resources/test-put.properties
+++ b/src/test/resources/test-put.properties
@@ -4,4 +4,7 @@ three=and escapes\n\t\r\f
\ with\ spaces=everywhere
altsep=value
multiline=one two three
+novalue=
+keyonly=
+=
key.4=ሴሴ
\ No newline at end of file
diff --git a/src/test/resources/test-putnew.properties b/src/test/resources/test-putnew.properties
index 59700cb..2ccaa90 100644
--- a/src/test/resources/test-putnew.properties
+++ b/src/test/resources/test-putnew.properties
@@ -13,5 +13,8 @@ altsep:value
multiline = one \
two \
three
+novalue=
+keyonly
+=
key.4 = \u1234ሴ
five=5
diff --git a/src/test/resources/test-putraw.properties b/src/test/resources/test-putraw.properties
index 61b173f..f513065 100644
--- a/src/test/resources/test-putraw.properties
+++ b/src/test/resources/test-putraw.properties
@@ -6,4 +6,7 @@ altsep=value
multiline=one \
two \
three
+novalue=
+keyonly=
+=
key.4=\u1234ሴ
\ No newline at end of file
diff --git a/src/test/resources/test-removecomment.properties b/src/test/resources/test-removecomment.properties
index 9e8acbb..7add4bb 100644
--- a/src/test/resources/test-removecomment.properties
+++ b/src/test/resources/test-removecomment.properties
@@ -12,4 +12,7 @@ altsep:value
multiline = one \
two \
three
+novalue=
+keyonly
+=
key.4 = \u1234ሴ
diff --git a/src/test/resources/test-removefirst.properties b/src/test/resources/test-removefirst.properties
index c81ca16..7754d0c 100644
--- a/src/test/resources/test-removefirst.properties
+++ b/src/test/resources/test-removefirst.properties
@@ -11,4 +11,7 @@ altsep:value
multiline = one \
two \
three
+novalue=
+keyonly
+=
key.4 = \u1234ሴ
diff --git a/src/test/resources/test-removelast.properties b/src/test/resources/test-removelast.properties
index 6411934..d60258f 100644
--- a/src/test/resources/test-removelast.properties
+++ b/src/test/resources/test-removelast.properties
@@ -13,3 +13,6 @@ altsep:value
multiline = one \
two \
three
+novalue=
+keyonly
+=
diff --git a/src/test/resources/test-removemiddle.properties b/src/test/resources/test-removemiddle.properties
index d521515..4c97b20 100644
--- a/src/test/resources/test-removemiddle.properties
+++ b/src/test/resources/test-removemiddle.properties
@@ -9,4 +9,7 @@ altsep:value
multiline = one \
two \
three
+novalue=
+keyonly
+=
key.4 = \u1234ሴ
diff --git a/src/test/resources/test-separatoratend-putnew.properties b/src/test/resources/test-separatoratend-putnew.properties
index 18e90c3..dc4561f 100644
--- a/src/test/resources/test-separatoratend-putnew.properties
+++ b/src/test/resources/test-separatoratend-putnew.properties
@@ -13,6 +13,9 @@ altsep:value
multiline = one \
two \
three
+novalue=
+keyonly
+=
key.4 = \u1234ሴ
separator.at.end=
five=5
\ No newline at end of file
diff --git a/src/test/resources/test-separatoratend.properties b/src/test/resources/test-separatoratend.properties
index cc9bfcd..837d10b 100644
--- a/src/test/resources/test-separatoratend.properties
+++ b/src/test/resources/test-separatoratend.properties
@@ -13,5 +13,8 @@ altsep:value
multiline = one \
two \
three
+novalue=
+keyonly
+=
key.4 = \u1234ሴ
separator.at.end=
\ No newline at end of file
diff --git a/src/test/resources/test-setproperty.properties b/src/test/resources/test-setproperty.properties
index e4433fa..100be1c 100644
--- a/src/test/resources/test-setproperty.properties
+++ b/src/test/resources/test-setproperty.properties
@@ -8,4 +8,7 @@ three=and escapes\n\t\r\f
\ with\ spaces=everywhere
altsep=value
multiline=one two three
+novalue=
+keyonly=
+=
key.4=ሴሴ
\ No newline at end of file
diff --git a/src/test/resources/test-storeheader.properties b/src/test/resources/test-storeheader.properties
index ceb3ad3..9c92b85 100644
--- a/src/test/resources/test-storeheader.properties
+++ b/src/test/resources/test-storeheader.properties
@@ -12,4 +12,7 @@ altsep:value
multiline = one \
two \
three
+novalue=
+keyonly
+=
key.4 = \u1234ሴ
diff --git a/src/test/resources/test-unescaped.properties b/src/test/resources/test-unescaped.properties
index 32374cd..24787fb 100644
--- a/src/test/resources/test-unescaped.properties
+++ b/src/test/resources/test-unescaped.properties
@@ -13,4 +13,7 @@ altsep:value
multiline = one \
two \
three
+novalue=
+keyonly
+=
key.4 = ሴሴ
diff --git a/src/test/resources/test.properties b/src/test/resources/test.properties
index 990d4a6..9346256 100644
--- a/src/test/resources/test.properties
+++ b/src/test/resources/test.properties
@@ -13,4 +13,7 @@ altsep:value
multiline = one \
two \
three
+novalue=
+keyonly
+=
key.4 = \u1234ሴ
diff --git a/src/test/resources/test2-putnew.properties b/src/test/resources/test2-putnew.properties
index 5e960de..195c451 100644
--- a/src/test/resources/test2-putnew.properties
+++ b/src/test/resources/test2-putnew.properties
@@ -13,6 +13,9 @@ altsep:value
multiline = one \
two \
three
+novalue=
+keyonly
+=
key.4 = \u1234ሴ
five=5
# final comment
diff --git a/src/test/resources/test2.properties b/src/test/resources/test2.properties
index f2d73bd..d53b594 100644
--- a/src/test/resources/test2.properties
+++ b/src/test/resources/test2.properties
@@ -13,5 +13,8 @@ altsep:value
multiline = one \
two \
three
+novalue=
+keyonly
+=
key.4 = \u1234ሴ
# final comment
diff --git a/src/test/resources/test3-putnew.properties b/src/test/resources/test3-putnew.properties
index ec400f0..43dde73 100644
--- a/src/test/resources/test3-putnew.properties
+++ b/src/test/resources/test3-putnew.properties
@@ -13,5 +13,8 @@ altsep:value
multiline = one \
two \
three
+novalue=
+keyonly
+=
key.4 = \u1234ሴ
five=5
\ No newline at end of file
diff --git a/src/test/resources/test3.properties b/src/test/resources/test3.properties
index 467c4d3..d409cbf 100644
--- a/src/test/resources/test3.properties
+++ b/src/test/resources/test3.properties
@@ -13,4 +13,7 @@ altsep:value
multiline = one \
two \
three
+novalue=
+keyonly
+=
key.4 = \u1234ሴ
\ No newline at end of file
diff --git a/src/test/resources/testcrlf-storeheader.properties b/src/test/resources/testcrlf-storeheader.properties
index ceb3ad3..9c92b85 100644
--- a/src/test/resources/testcrlf-storeheader.properties
+++ b/src/test/resources/testcrlf-storeheader.properties
@@ -12,4 +12,7 @@ altsep:value
multiline = one \
two \
three
+novalue=
+keyonly
+=
key.4 = \u1234ሴ
diff --git a/src/test/resources/testcrlf.properties b/src/test/resources/testcrlf.properties
index 990d4a6..9346256 100644
--- a/src/test/resources/testcrlf.properties
+++ b/src/test/resources/testcrlf.properties
@@ -13,4 +13,7 @@ altsep:value
multiline = one \
two \
three
+novalue=
+keyonly
+=
key.4 = \u1234ሴ