Merge changes I8e406f9d,If0950347,Ic09dc2ab

* changes:
  Implement XML parsing for open formula
  Implement XML parsing for atomic formula
  Add getters for atomic formula components
This commit is contained in:
Khaled Abdelmohsen
2019-11-13 13:43:36 +00:00
committed by Android (Google) Code Review
5 changed files with 580 additions and 59 deletions

View File

@@ -177,6 +177,14 @@ public abstract class AtomicFormula implements Formula {
dest.writeInt(mOperator);
}
public int getValue() {
return mValue;
}
public int getOperator() {
return mOperator;
}
private int getMetadataValueByKey(AppInstallMetadata appInstallMetadata) {
switch (getKey()) {
case VERSION_CODE:
@@ -271,6 +279,10 @@ public abstract class AtomicFormula implements Formula {
dest.writeStringNoHelper(mValue);
}
public String getValue() {
return mValue;
}
private String getMetadataValueByKey(AppInstallMetadata appInstallMetadata) {
switch (getKey()) {
case PACKAGE_NAME:
@@ -367,6 +379,10 @@ public abstract class AtomicFormula implements Formula {
dest.writeByte((byte) (mValue ? 1 : 0));
}
public boolean getValue() {
return mValue;
}
private boolean getMetadataValueByKey(AppInstallMetadata appInstallMetadata) {
switch (getKey()) {
case PRE_INSTALLED:

View File

@@ -0,0 +1,32 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* 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.android.server.integrity.parser;
import android.annotation.NonNull;
/**
* Thrown when rule parsing fails.
*/
public class RuleParseException extends Exception {
public RuleParseException(@NonNull String message) {
super(message);
}
public RuleParseException(@NonNull String message, @NonNull Throwable cause) {
super(message, cause);
}
}

View File

@@ -25,8 +25,8 @@ import java.util.List;
public interface RuleParser {
/** Parse rules from a string. */
List<Rule> parse(String ruleText);
List<Rule> parse(String ruleText) throws RuleParseException;
/** Parse rules from an input stream. */
List<Rule> parse(InputStream inputStream);
List<Rule> parse(InputStream inputStream) throws RuleParseException;
}

View File

@@ -16,9 +16,11 @@
package com.android.server.integrity.parser;
import android.util.Slog;
import android.util.Xml;
import com.android.server.integrity.model.AtomicFormula;
import com.android.server.integrity.model.Formula;
import com.android.server.integrity.model.OpenFormula;
import com.android.server.integrity.model.Rule;
import org.xmlpull.v1.XmlPullParser;
@@ -38,34 +40,41 @@ public final class RuleXmlParser implements RuleParser {
public static final String TAG = "RuleXmlParser";
// TODO: Use XML attributes
private static final String RULE_LIST_TAG = "RuleList";
private static final String RULE_TAG = "Rule";
private static final String OPEN_FORMULA_TAG = "OpenFormula";
private static final String ATOMIC_FORMULA_TAG = "AtomicFormula";
private static final String EFFECT_TAG = "Effect";
private static final String KEY_TAG = "Key";
private static final String OPERATOR_TAG = "Operator";
private static final String VALUE_TAG = "Value";
private static final String CONNECTOR_TAG = "Connector";
@Override
public List<Rule> parse(String ruleText) {
public List<Rule> parse(String ruleText) throws RuleParseException {
try {
XmlPullParser xmlPullParser = Xml.newPullParser();
xmlPullParser.setInput(new StringReader(ruleText));
return parseRules(xmlPullParser);
} catch (XmlPullParserException | IOException e) {
Slog.e(TAG, String.format("Unable to read rules from string: %s", ruleText), e);
} catch (Exception e) {
throw new RuleParseException(e.getMessage(), e);
}
return null;
}
@Override
public List<Rule> parse(InputStream inputStream) {
public List<Rule> parse(InputStream inputStream) throws RuleParseException {
try {
XmlPullParser xmlPullParser = Xml.newPullParser();
xmlPullParser.setInput(inputStream, StandardCharsets.UTF_8.name());
return parseRules(xmlPullParser);
} catch (XmlPullParserException | IOException e) {
Slog.e(TAG, "Unable to read rules from stream", e);
} catch (Exception e) {
throw new RuleParseException(e.getMessage(), e);
}
return null;
}
private List<Rule> parseRules(XmlPullParser parser) throws IOException, XmlPullParserException {
private static List<Rule> parseRules(XmlPullParser parser)
throws IOException, XmlPullParserException {
List<Rule> rules = new ArrayList<>();
// Skipping the first event type, which is always {@link XmlPullParser.START_DOCUMENT}
@@ -89,17 +98,150 @@ public final class RuleXmlParser implements RuleParser {
if (eventType != XmlPullParser.START_TAG || !nodeName.equals(RULE_TAG)) {
continue;
}
Rule parsedRule = parseRule(parser);
if (parsedRule != null) {
rules.add(parsedRule);
}
rules.add(parseRule(parser));
}
return rules;
}
private Rule parseRule(XmlPullParser parser) {
// TODO: Implement rule parser.
return null;
private static Rule parseRule(XmlPullParser parser) throws IOException, XmlPullParserException {
Formula formula = null;
@Rule.Effect int effect = 0;
int eventType;
while ((eventType = parser.next()) != XmlPullParser.END_DOCUMENT) {
String nodeName = parser.getName();
if (eventType == XmlPullParser.END_TAG && parser.getName().equals(RULE_TAG)) {
break;
}
if (eventType == XmlPullParser.START_TAG) {
switch (nodeName) {
case OPEN_FORMULA_TAG:
formula = parseOpenFormula(parser);
break;
case ATOMIC_FORMULA_TAG:
formula = parseAtomicFormula(parser);
break;
case EFFECT_TAG:
effect = Integer.parseInt(extractValue(parser));
break;
default:
throw new RuntimeException(
String.format("Found unexpected tag: %s", nodeName));
}
} else {
throw new RuntimeException(
String.format("Found unexpected event type: %d", eventType));
}
}
return new Rule(formula, effect);
}
private static Formula parseOpenFormula(XmlPullParser parser)
throws IOException, XmlPullParserException {
@OpenFormula.Connector int connector = 0;
List<Formula> formulas = new ArrayList<>();
int eventType;
while ((eventType = parser.next()) != XmlPullParser.END_DOCUMENT) {
String nodeName = parser.getName();
if (eventType == XmlPullParser.END_TAG && parser.getName().equals(OPEN_FORMULA_TAG)) {
break;
}
if (eventType == XmlPullParser.START_TAG) {
switch (nodeName) {
case CONNECTOR_TAG:
connector = Integer.parseInt(extractValue(parser));
break;
case ATOMIC_FORMULA_TAG:
formulas.add(parseAtomicFormula(parser));
break;
case OPEN_FORMULA_TAG:
formulas.add(parseOpenFormula(parser));
break;
default:
throw new RuntimeException(
String.format("Found unexpected tag: %s", nodeName));
}
} else {
throw new RuntimeException(
String.format("Found unexpected event type: %d", eventType));
}
}
return new OpenFormula(connector, formulas);
}
private static Formula parseAtomicFormula(XmlPullParser parser)
throws IOException, XmlPullParserException {
@AtomicFormula.Key int key = 0;
@AtomicFormula.Operator int operator = 0;
String value = null;
int eventType;
while ((eventType = parser.next()) != XmlPullParser.END_DOCUMENT) {
String nodeName = parser.getName();
if (eventType == XmlPullParser.END_TAG && parser.getName().equals(ATOMIC_FORMULA_TAG)) {
break;
}
if (eventType == XmlPullParser.START_TAG) {
switch (nodeName) {
case KEY_TAG:
key = Integer.parseInt(extractValue(parser));
break;
case OPERATOR_TAG:
operator = Integer.parseInt(extractValue(parser));
break;
case VALUE_TAG:
value = extractValue(parser);
break;
default:
throw new RuntimeException(
String.format("Found unexpected tag: %s", nodeName));
}
} else {
throw new RuntimeException(
String.format("Found unexpected event type: %d", eventType));
}
}
return constructAtomicFormulaBasedOnKey(key, operator, value);
}
private static Formula constructAtomicFormulaBasedOnKey(@AtomicFormula.Key int key,
@AtomicFormula.Operator int operator, String value) {
switch (key) {
case AtomicFormula.PACKAGE_NAME:
case AtomicFormula.INSTALLER_NAME:
case AtomicFormula.APP_CERTIFICATE:
case AtomicFormula.INSTALLER_CERTIFICATE:
return new AtomicFormula.StringAtomicFormula(key, value);
case AtomicFormula.PRE_INSTALLED:
return new AtomicFormula.BooleanAtomicFormula(key, Boolean.parseBoolean(value));
case AtomicFormula.VERSION_CODE:
return new AtomicFormula.IntAtomicFormula(key, operator, Integer.parseInt(value));
default:
throw new RuntimeException(String.format("Found unexpected key: %d", key));
}
}
private static String extractValue(XmlPullParser parser)
throws IOException, XmlPullParserException {
String value;
int eventType = parser.next();
if (eventType == XmlPullParser.TEXT) {
value = parser.getText();
eventType = parser.next();
if (eventType == XmlPullParser.END_TAG) {
return value;
}
}
throw new RuntimeException(String.format("Found unexpected event type: %d", eventType));
}
}

View File

@@ -18,9 +18,10 @@ package com.android.server.integrity.parser;
import static com.android.server.testutils.TestUtils.assertExpectException;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static com.google.common.truth.Truth.assertThat;
import com.android.server.integrity.model.AtomicFormula;
import com.android.server.integrity.model.OpenFormula;
import com.android.server.integrity.model.Rule;
import org.junit.Test;
@@ -29,63 +30,393 @@ import org.junit.runners.JUnit4;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@RunWith(JUnit4.class)
public class RuleXmlParserTest {
private static final String VALID_RULE_XML = "<RuleList>"
+ "<Rule>"
+ "<OpenFormula>"
+ "<Connector>NOT</Connector>"
+ "<AtomicFormula>"
+ "<Key>PACKAGE_NAME</Key>"
+ "<Operator>EQ</Operator>"
+ "<Value>com.app.test</Value>"
+ "</AtomicFormula>"
+ "</OpenFormula>"
+ "<Effect>DENY</Effect>"
+ "</Rule>"
+ "</RuleList>";
@Test
public void testXmlString_validRule() {
public void testXmlStream_validOpenFormula() throws Exception {
String ruleXmlOpenFormula = "<RuleList>"
+ "<Rule>"
+ "<OpenFormula>"
+ "<Connector>" + OpenFormula.NOT + "</Connector>"
+ "<AtomicFormula>"
+ "<Key>" + AtomicFormula.PACKAGE_NAME + "</Key>"
+ "<Operator>" + AtomicFormula.EQ + "</Operator>"
+ "<Value>com.app.test</Value>"
+ "</AtomicFormula>"
+ "</OpenFormula>"
+ "<Effect>" + Rule.DENY + "</Effect>"
+ "</Rule>"
+ "</RuleList>";
RuleParser xmlParser = new RuleXmlParser();
List<Rule> rules = xmlParser.parse(VALID_RULE_XML);
assertNotNull(rules);
assertTrue(rules.isEmpty());
}
@Test
public void testXmlStream_validRule() {
RuleParser xmlParser = new RuleXmlParser();
InputStream inputStream = new ByteArrayInputStream(VALID_RULE_XML.getBytes());
InputStream inputStream = new ByteArrayInputStream(ruleXmlOpenFormula.getBytes());
Rule expectedRule = new Rule(new OpenFormula(OpenFormula.NOT, Collections.singletonList(
new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME, "com.app.test"))),
Rule.DENY);
List<Rule> rules = xmlParser.parse(inputStream);
assertNotNull(rules);
assertTrue(rules.isEmpty());
assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
}
@Test
public void testXmlString_validOpenFormula_notConnector() throws Exception {
String ruleXmlOpenFormula = "<RuleList>"
+ "<Rule>"
+ "<OpenFormula>"
+ "<Connector>" + OpenFormula.NOT + "</Connector>"
+ "<AtomicFormula>"
+ "<Key>" + AtomicFormula.PACKAGE_NAME + "</Key>"
+ "<Operator>" + AtomicFormula.EQ + "</Operator>"
+ "<Value>com.app.test</Value>"
+ "</AtomicFormula>"
+ "</OpenFormula>"
+ "<Effect>" + Rule.DENY + "</Effect>"
+ "</Rule>"
+ "</RuleList>";
RuleParser xmlParser = new RuleXmlParser();
Rule expectedRule = new Rule(new OpenFormula(OpenFormula.NOT, Collections.singletonList(
new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME, "com.app.test"))),
Rule.DENY);
List<Rule> rules = xmlParser.parse(ruleXmlOpenFormula);
assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
}
@Test
public void testXmlString_validOpenFormula_andConnector() throws Exception {
String ruleXmlOpenFormula = "<RuleList>"
+ "<Rule>"
+ "<OpenFormula>"
+ "<Connector>" + OpenFormula.AND + "</Connector>"
+ "<AtomicFormula>"
+ "<Key>" + AtomicFormula.PACKAGE_NAME + "</Key>"
+ "<Operator>" + AtomicFormula.EQ + "</Operator>"
+ "<Value>com.app.test</Value>"
+ "</AtomicFormula>"
+ "<AtomicFormula>"
+ "<Key>" + AtomicFormula.APP_CERTIFICATE + "</Key>"
+ "<Operator>" + AtomicFormula.EQ + "</Operator>"
+ "<Value>test_cert</Value>"
+ "</AtomicFormula>"
+ "</OpenFormula>"
+ "<Effect>" + Rule.DENY + "</Effect>"
+ "</Rule>"
+ "</RuleList>";
RuleParser xmlParser = new RuleXmlParser();
Rule expectedRule = new Rule(new OpenFormula(OpenFormula.AND, Arrays.asList(
new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME, "com.app.test"),
new AtomicFormula.StringAtomicFormula(AtomicFormula.APP_CERTIFICATE, "test_cert"))),
Rule.DENY);
List<Rule> rules = xmlParser.parse(ruleXmlOpenFormula);
assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
}
@Test
public void testXmlString_validOpenFormula_orConnector() throws Exception {
String ruleXmlOpenFormula = "<RuleList>"
+ "<Rule>"
+ "<OpenFormula>"
+ "<Connector>" + OpenFormula.OR + "</Connector>"
+ "<AtomicFormula>"
+ "<Key>" + AtomicFormula.PACKAGE_NAME + "</Key>"
+ "<Operator>" + AtomicFormula.EQ + "</Operator>"
+ "<Value>com.app.test</Value>"
+ "</AtomicFormula>"
+ "<AtomicFormula>"
+ "<Key>" + AtomicFormula.APP_CERTIFICATE + "</Key>"
+ "<Operator>" + AtomicFormula.EQ + "</Operator>"
+ "<Value>test_cert</Value>"
+ "</AtomicFormula>"
+ "</OpenFormula>"
+ "<Effect>" + Rule.DENY + "</Effect>"
+ "</Rule>"
+ "</RuleList>";
RuleParser xmlParser = new RuleXmlParser();
Rule expectedRule = new Rule(new OpenFormula(OpenFormula.OR, Arrays.asList(
new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME, "com.app.test"),
new AtomicFormula.StringAtomicFormula(AtomicFormula.APP_CERTIFICATE, "test_cert"))),
Rule.DENY);
List<Rule> rules = xmlParser.parse(ruleXmlOpenFormula);
assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
}
@Test
public void testXmlString_validOpenFormula_differentTagOrder() throws Exception {
String ruleXmlOpenFormula = "<RuleList>"
+ "<Rule>"
+ "<OpenFormula>"
+ "<AtomicFormula>"
+ "<Key>" + AtomicFormula.PACKAGE_NAME + "</Key>"
+ "<Operator>" + AtomicFormula.EQ + "</Operator>"
+ "<Value>com.app.test</Value>"
+ "</AtomicFormula>"
+ "<Connector>" + OpenFormula.NOT + "</Connector>"
+ "</OpenFormula>"
+ "<Effect>" + Rule.DENY + "</Effect>"
+ "</Rule>"
+ "</RuleList>";
RuleParser xmlParser = new RuleXmlParser();
Rule expectedRule = new Rule(new OpenFormula(OpenFormula.NOT, Collections.singletonList(
new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME, "com.app.test"))),
Rule.DENY);
List<Rule> rules = xmlParser.parse(ruleXmlOpenFormula);
assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
}
@Test
public void testXmlString_invalidOpenFormula_invalidNumberOfFormulas() throws Exception {
String ruleXmlOpenFormula = "<RuleList>"
+ "<Rule>"
+ "<OpenFormula>"
+ "<Connector>" + OpenFormula.NOT + "</Connector>"
+ "<AtomicFormula>"
+ "<Key>" + AtomicFormula.PACKAGE_NAME + "</Key>"
+ "<Operator>" + AtomicFormula.EQ + "</Operator>"
+ "<Value>com.app.test</Value>"
+ "</AtomicFormula>"
+ "<AtomicFormula>"
+ "<Key>" + AtomicFormula.VERSION_CODE + "</Key>"
+ "<Operator>" + AtomicFormula.EQ + "</Operator>"
+ "<Value>1</Value>"
+ "</AtomicFormula>"
+ "</OpenFormula>"
+ "<Effect>" + Rule.DENY + "</Effect>"
+ "</Rule>"
+ "</RuleList>";
RuleParser xmlParser = new RuleXmlParser();
assertExpectException(
RuleParseException.class,
/* expectedExceptionMessageRegex */ "Connector NOT must have 1 formula only",
() -> xmlParser.parse(ruleXmlOpenFormula));
}
@Test
public void testXmlString_invalidOpenFormula_invalidOperator() throws Exception {
String ruleXmlOpenFormula = "<RuleList>"
+ "<Rule>"
+ "<OpenFormula>"
+ "<Connector>" + OpenFormula.NOT + "</Connector>"
+ "<AtomicFormula>"
+ "<Key>" + AtomicFormula.PACKAGE_NAME + "</Key>"
+ "<Operator>INVALID_OPERATOR</Operator>"
+ "<Value>com.app.test</Value>"
+ "</AtomicFormula>"
+ "</OpenFormula>"
+ "<Effect>" + Rule.DENY + "</Effect>"
+ "</Rule>"
+ "</RuleList>";
RuleParser xmlParser = new RuleXmlParser();
assertExpectException(
RuleParseException.class,
/* expectedExceptionMessageRegex */ "For input string: \"INVALID_OPERATOR\"",
() -> xmlParser.parse(ruleXmlOpenFormula));
}
@Test
public void testXmlString_invalidOpenFormula_invalidEffect() throws Exception {
String ruleXmlOpenFormula = "<RuleList>"
+ "<Rule>"
+ "<OpenFormula>"
+ "<Connector>" + OpenFormula.NOT + "</Connector>"
+ "<AtomicFormula>"
+ "<Key>" + AtomicFormula.PACKAGE_NAME + "</Key>"
+ "<Operator>" + AtomicFormula.EQ + "</Operator>"
+ "<Value>com.app.test</Value>"
+ "</AtomicFormula>"
+ "</OpenFormula>"
+ "<Effect>INVALID_EFFECT</Effect>"
+ "</Rule>"
+ "</RuleList>";
RuleParser xmlParser = new RuleXmlParser();
assertExpectException(
RuleParseException.class,
/* expectedExceptionMessageRegex */ "For input string: \"INVALID_EFFECT\"",
() -> xmlParser.parse(ruleXmlOpenFormula));
}
@Test
public void testXmlString_invalidOpenFormula_invalidTags() throws Exception {
String ruleXmlOpenFormula = "<RuleList>"
+ "<Rule>"
+ "<OpenFormula>"
+ "<InvalidConnector>" + OpenFormula.NOT + "</InvalidConnector>"
+ "<AtomicFormula>"
+ "<Key>" + AtomicFormula.PACKAGE_NAME + "</Key>"
+ "<Operator>" + AtomicFormula.EQ + "</Operator>"
+ "<Value>com.app.test</Value>"
+ "</AtomicFormula>"
+ "</OpenFormula>"
+ "<Effect>" + Rule.DENY + "</Effect>"
+ "</Rule>"
+ "</RuleList>";
RuleParser xmlParser = new RuleXmlParser();
assertExpectException(
RuleParseException.class,
/* expectedExceptionMessageRegex */ "Found unexpected tag: InvalidConnector",
() -> xmlParser.parse(ruleXmlOpenFormula));
}
@Test
public void testXmlString_validAtomicFormula_stringValue() throws Exception {
String ruleXmlAtomicFormula = "<RuleList>"
+ "<Rule>"
+ "<AtomicFormula>"
+ "<Key>" + AtomicFormula.PACKAGE_NAME + "</Key>"
+ "<Operator>" + AtomicFormula.EQ + "</Operator>"
+ "<Value>com.app.test</Value>"
+ "</AtomicFormula>"
+ "<Effect>" + Rule.DENY + "</Effect>"
+ "</Rule>"
+ "</RuleList>";
RuleParser xmlParser = new RuleXmlParser();
Rule expectedRule = new Rule(
new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME, "com.app.test"),
Rule.DENY);
List<Rule> rules = xmlParser.parse(ruleXmlAtomicFormula);
assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
}
@Test
public void testXmlString_validAtomicFormula_integerValue() throws Exception {
String ruleXmlAtomicFormula = "<RuleList>"
+ "<Rule>"
+ "<AtomicFormula>"
+ "<Key>" + AtomicFormula.VERSION_CODE + "</Key>"
+ "<Operator>" + AtomicFormula.EQ + "</Operator>"
+ "<Value>1</Value>"
+ "</AtomicFormula>"
+ "<Effect>" + Rule.DENY + "</Effect>"
+ "</Rule>"
+ "</RuleList>";
RuleParser xmlParser = new RuleXmlParser();
Rule expectedRule = new Rule(
new AtomicFormula.IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.EQ, 1),
Rule.DENY);
List<Rule> rules = xmlParser.parse(ruleXmlAtomicFormula);
assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
}
@Test
public void testXmlString_validAtomicFormula_booleanValue() throws Exception {
String ruleXmlAtomicFormula = "<RuleList>"
+ "<Rule>"
+ "<AtomicFormula>"
+ "<Key>" + AtomicFormula.PRE_INSTALLED + "</Key>"
+ "<Operator>" + AtomicFormula.EQ + "</Operator>"
+ "<Value>true</Value>"
+ "</AtomicFormula>"
+ "<Effect>" + Rule.DENY + "</Effect>"
+ "</Rule>"
+ "</RuleList>";
RuleParser xmlParser = new RuleXmlParser();
Rule expectedRule = new Rule(
new AtomicFormula.BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, true),
Rule.DENY);
List<Rule> rules = xmlParser.parse(ruleXmlAtomicFormula);
assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
}
@Test
public void testXmlString_validAtomicFormula_differentTagOrder() throws Exception {
String ruleXmlAtomicFormula = "<RuleList>"
+ "<Rule>"
+ "<AtomicFormula>"
+ "<Operator>" + AtomicFormula.EQ + "</Operator>"
+ "<Value>com.app.test</Value>"
+ "<Key>" + AtomicFormula.PACKAGE_NAME + "</Key>"
+ "</AtomicFormula>"
+ "<Effect>" + Rule.DENY + "</Effect>"
+ "</Rule>"
+ "</RuleList>";
RuleParser xmlParser = new RuleXmlParser();
Rule expectedRule = new Rule(
new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME, "com.app.test"),
Rule.DENY);
List<Rule> rules = xmlParser.parse(ruleXmlAtomicFormula);
assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
}
@Test
public void testXmlString_invalidAtomicFormula_invalidTags() throws Exception {
String ruleXmlAtomicFormula = "<RuleList>"
+ "<Rule>"
+ "<AtomicFormula>"
+ "<BadKey>" + AtomicFormula.PACKAGE_NAME + "</BadKey>"
+ "<Operator>" + AtomicFormula.EQ + "</Operator>"
+ "<Value>com.app.test</Value>"
+ "</AtomicFormula>"
+ "<Effect>" + Rule.DENY + "</Effect>"
+ "</Rule>"
+ "</RuleList>";
RuleParser xmlParser = new RuleXmlParser();
assertExpectException(
RuleParseException.class,
/* expectedExceptionMessageRegex */ "Found unexpected tag: BadKey",
() -> xmlParser.parse(ruleXmlAtomicFormula));
}
@Test
public void testXmlString_invalidAtomicFormula() throws Exception {
String ruleXmlAtomicFormula = "<RuleList>"
+ "<Rule>"
+ "<AtomicFormula>"
+ "<Key>" + AtomicFormula.VERSION_CODE + "</Key>"
+ "<Operator>" + AtomicFormula.EQ + "</Operator>"
+ "<Value>com.app.test</Value>"
+ "</AtomicFormula>"
+ "<Effect>" + Rule.DENY + "</Effect>"
+ "</Rule>"
+ "</RuleList>";
RuleParser xmlParser = new RuleXmlParser();
assertExpectException(
RuleParseException.class,
/* expectedExceptionMessageRegex */ "For input string: \"com.app.test\"",
() -> xmlParser.parse(ruleXmlAtomicFormula));
}
@Test
public void testXmlString_withNoRuleList() {
String ruleXmlWithNoRuleList = "<Rule>"
+ "<OpenFormula>"
+ "<Connector>NOT</Connector>"
+ "<Connector>" + OpenFormula.NOT + "</Connector>"
+ "<AtomicFormula>"
+ "<Key>PACKAGE_NAME</Key>"
+ "<Operator>EQ</Operator>"
+ "<Key>" + AtomicFormula.PACKAGE_NAME + "</Key>"
+ "<Operator>" + AtomicFormula.EQ + "</Operator>"
+ "<Value>com.app.test</Value>"
+ "</AtomicFormula>"
+ "</OpenFormula>"
+ "<Effect>DENY</Effect>"
+ "<Effect>" + Rule.DENY + "</Effect>"
+ "</Rule>";
RuleParser xmlParser = new RuleXmlParser();
assertExpectException(
RuntimeException.class,
RuleParseException.class,
/* expectedExceptionMessageRegex */ "Rules must start with <RuleList> tag.",
() -> xmlParser.parse(ruleXmlWithNoRuleList));
}
@@ -94,20 +425,20 @@ public class RuleXmlParserTest {
public void testXmlStream_withNoRuleList() {
String ruleXmlWithNoRuleList = "<Rule>"
+ "<OpenFormula>"
+ "<Connector>NOT</Connector>"
+ "<Connector>" + OpenFormula.NOT + "</Connector>"
+ "<AtomicFormula>"
+ "<Key>PACKAGE_NAME</Key>"
+ "<Operator>EQ</Operator>"
+ "<Key>" + AtomicFormula.PACKAGE_NAME + "</Key>"
+ "<Operator>" + AtomicFormula.EQ + "</Operator>"
+ "<Value>com.app.test</Value>"
+ "</AtomicFormula>"
+ "</OpenFormula>"
+ "<Effect>DENY</Effect>"
+ "<Effect>" + Rule.DENY + "</Effect>"
+ "</Rule>";
InputStream inputStream = new ByteArrayInputStream(ruleXmlWithNoRuleList.getBytes());
RuleParser xmlParser = new RuleXmlParser();
assertExpectException(
RuntimeException.class,
RuleParseException.class,
/* expectedExceptionMessageRegex */ "Rules must start with <RuleList> tag.",
() -> xmlParser.parse(inputStream));
}