Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug 565011 rebuild the core of condition expression evaluation #299

Merged
merged 1 commit into from
Jul 9, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,10 @@
* at all ({@code Emission.failed()}) and then request either permissions or
* failure details.
* </p>
*
* <p>
* Any implementation must follow the contract defined in
* {@code EmissionContractTest}
* </p>
*/
public interface Emission {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@

import org.eclipse.passage.lic.internal.api.registry.Service;

/**
* Any implementation must follow the contract defined in
* {@code ExpressionEvaluationServiceContractTest}
*/
public interface ExpressionEvaluationService extends Service<ExpressionProtocol> {

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@

import org.eclipse.passage.lic.internal.api.registry.Service;

/**
* An implementation must follow the contract defined in
* {@code ExpressionParsingServiceContractTest}
*/
public interface ExpressionParsingService extends Service<ExpressionProtocol> {

ParsedExpression parsed(String expression) throws ExpressionParsingException;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@
import org.eclipse.passage.lic.internal.api.conditions.evaluation.ParsedExpression;

@SuppressWarnings("restriction")
final class SimpleMapExpression implements ParsedExpression {
public final class SimpleMapExpression implements ParsedExpression {

private final Map<String, String> checks;
private final ExpressionProtocol format;

SimpleMapExpression(ExpressionProtocol format, Map<String, String> checks) {
public SimpleMapExpression(ExpressionProtocol format, Map<String, String> checks) {
Objects.requireNonNull(format);
Objects.requireNonNull(checks);
this.format = format;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
*******************************************************************************/
package org.eclipse.passage.lic.internal.base.conditions.evaluation;

import java.util.Objects;

import org.eclipse.passage.lic.internal.api.conditions.evaluation.ExpressionEvaluationException;
import org.eclipse.passage.lic.internal.api.conditions.evaluation.ExpressionEvaluationService;
import org.eclipse.passage.lic.internal.api.conditions.evaluation.ExpressionProtocol;
Expand All @@ -32,6 +34,9 @@ public ExpressionProtocol id() {
@Override
public void evaluate(ParsedExpression expression, ExpressionTokenAssessmentService assessor)
throws ExpressionEvaluationException {
Objects.requireNonNull(expression);
Objects.requireNonNull(assessor);
verifyProtocol(expression);
SimpleMapExpression map = map(expression);
for (String key : map.keys()) {
boolean passed = equal(key, map.expected(key), assessor);
Expand All @@ -56,16 +61,25 @@ private boolean equal(String key, String value, ExpressionTokenAssessmentService

private SimpleMapExpression map(ParsedExpression expression) throws ExpressionEvaluationException {
if (!SimpleMapExpression.class.isInstance(expression)) {
new ExpressionEvaluationException(String.format(ConditionsEvaluationMessages.getString(//
throw new ExpressionEvaluationException(String.format(ConditionsEvaluationMessages.getString(//
"SimpleMapExpressionEvaluationService.foreign_expression"), // //$NON-NLS-1$
expression.protocol()));
}
SimpleMapExpression map = (SimpleMapExpression) expression;
if (map.keys().isEmpty()) {
new ExpressionEvaluationException(ConditionsEvaluationMessages.getString(//
throw new ExpressionEvaluationException(ConditionsEvaluationMessages.getString(//
"SimpleMapExpressionEvaluationService.no_checks")); //$NON-NLS-1$
}
return map;
}

private void verifyProtocol(ParsedExpression expression) throws ExpressionEvaluationException {
if (!id().equals(expression.protocol())) {
throw new ExpressionEvaluationException(String.format(
ConditionsEvaluationMessages
.getString("SimpleMapExpressionEvaluationService.unexpected_expression_protocol"), //$NON-NLS-1$
expression.protocol(), id()));
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ SimpleMapExpressionEvaluationService.foreign_expression=Expression protocol [%s]
SimpleMapExpressionEvaluationService.no_checks=Expression is invalid: it contains no checks
SimpleMapExpressionEvaluationService.segment_fails_evaluation=Expression fails evaluation (type %s) on segment [%s = %s]
SimpleMapExpressionEvaluationService.evaluation_fails=Expression segment [%s = %s] %s assessment failed with error
SimpleMapExpressionEvaluationService.unexpected_expression_protocol=Unexpected expression protocol [%s] (should be [%s])
AndsProtocolExpressionParseService.invalid_format=Segment [%s] is corrupted. Expected to have key=value structure.
AndsProtocolExpressionParseService.no_checks=Expression [%s] contains no checks. Expected to be of [key=value;...key=value] structure.
BasePermissionEmittingService.failed=Failed to assess expression [%s]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*******************************************************************************
* Copyright (c) 2020 ArSysOp
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* https://www.eclipse.org/legal/epl-2.0/.
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* ArSysOp - initial API and implementation
*******************************************************************************/
package org.eclipse.passage.lic.api.tests.conditions.evaluation;

import org.eclipse.passage.lic.api.tests.fakes.conditions.evaluation.FakePermission;
import org.eclipse.passage.lic.api.tests.fakes.diagnostic.FakeFailureDiagnostic;
import org.eclipse.passage.lic.internal.api.conditions.evaluation.Emission;

@SuppressWarnings("restriction")
public class EmissionImplsContractTest extends EmissionContractTest {

@Override
protected Emission failed() {
return new Emission.Failed(new FakeFailureDiagnostic());
}

@Override
protected Emission successful() {
return new Emission.Successful(new FakePermission());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*******************************************************************************
* Copyright (c) 2020 ArSysOp
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* https://www.eclipse.org/legal/epl-2.0/.
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* ArSysOp - initial API and implementation
*******************************************************************************/
package org.eclipse.passage.lic.api.tests.conditions.evaluation;

import static org.junit.Assert.fail;

import org.eclipse.passage.lic.api.tests.fakes.conditions.evaluation.FakeExpressionTokenAssessmentService;
import org.eclipse.passage.lic.api.tests.fakes.conditions.evaluation.FakeParsedExpression;
import org.eclipse.passage.lic.internal.api.conditions.evaluation.ExpressionEvaluationException;
import org.eclipse.passage.lic.internal.api.conditions.evaluation.ExpressionEvaluationService;
import org.eclipse.passage.lic.internal.api.conditions.evaluation.ExpressionTokenAssessmentService;
import org.eclipse.passage.lic.internal.api.conditions.evaluation.ParsedExpression;
import org.junit.Test;

@SuppressWarnings("restriction")
public abstract class ExpressionEvaluationServiceContractTest {

@Test(expected = NullPointerException.class)
public final void prohibitsNullExpression() {
prohibitsNullArgument(null, new FakeExpressionTokenAssessmentService());
}

@Test(expected = NullPointerException.class)
public final void prohibitsNullAssessor() {
prohibitsNullArgument(new FakeParsedExpression(), null);
}

@Test(expected = ExpressionEvaluationException.class)
public final void canOnlyEvaluateExpressionOfSameProtocl() throws ExpressionEvaluationException {
evaluator().evaluate(new FakeParsedExpression("fake"), //$NON-NLS-1$
new FakeExpressionTokenAssessmentService());
}

private void prohibitsNullArgument(ParsedExpression expression, ExpressionTokenAssessmentService assessor) {
try {
evaluator().evaluate(expression, assessor);
} catch (ExpressionEvaluationException e) {
fail("No evaluation activity is expected to be started for invalid incoming data"); //$NON-NLS-1$
}
}

protected abstract ExpressionEvaluationService evaluator();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*******************************************************************************
* Copyright (c) 2020 ArSysOp
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* https://www.eclipse.org/legal/epl-2.0/.
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* ArSysOp - initial API and implementation
*******************************************************************************/
package org.eclipse.passage.lic.api.tests.conditions.evaluation;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import org.eclipse.passage.lic.internal.api.conditions.evaluation.ExpressionParsingException;
import org.eclipse.passage.lic.internal.api.conditions.evaluation.ExpressionParsingService;
import org.eclipse.passage.lic.internal.api.conditions.evaluation.ParsedExpression;
import org.junit.Test;

@SuppressWarnings("restriction")
public abstract class ExpressionParsingServiceContractTest {

@Test(expected = ExpressionParsingException.class)
public final void blankExpressionCausesFailure() throws ExpressionParsingException {
parser().parsed("\t"); //$NON-NLS-1$
}

@Test(expected = NullPointerException.class)
public final void prohibitsNullExpression() throws ExpressionParsingException {
parser().parsed(null);
}

@Test
public final void producesSameProtocolResult() {
ExpressionParsingService parser = parser();
try {
assertEquals(parser.id(), parser.parsed(validExpression()).protocol());
} catch (ExpressionParsingException e) {
fail("Is not expected to fail on valid data"); //$NON-NLS-1$
}
}

@Test
public final void producesResultOfExpectedType() throws ExpressionParsingException {
assertTrue(resultType().isInstance(parser().parsed(validExpression())));
}

protected abstract ExpressionParsingService parser();

protected abstract String validExpression();

protected abstract Class<? extends ParsedExpression> resultType();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*******************************************************************************
* Copyright (c) 2020 ArSysOp
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* https://www.eclipse.org/legal/epl-2.0/.
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* ArSysOp - initial API and implementation
*******************************************************************************/
package org.eclipse.passage.lic.api.tests.fakes.conditions.evaluation;

import org.eclipse.passage.lic.internal.api.conditions.evaluation.ExpressionProtocol;
import org.eclipse.passage.lic.internal.api.conditions.evaluation.ParsedExpression;

@SuppressWarnings("restriction")
public final class FakeParsedExpression implements ParsedExpression {

private final ExpressionProtocol protocol;

public FakeParsedExpression(ExpressionProtocol protocol) {
this.protocol = protocol;
}

public FakeParsedExpression(String protocol) {
this(new ExpressionProtocol.Of(protocol));
}

public FakeParsedExpression() {
this(new ExpressionProtocol.Default());
}

@Override
public ExpressionProtocol protocol() {
return protocol;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*******************************************************************************
* Copyright (c) 2020 ArSysOp
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* https://www.eclipse.org/legal/epl-2.0/.
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* ArSysOp - initial API and implementation
*******************************************************************************/
package org.eclipse.passage.lic.internal.base.tests.conditions.evaluation;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;

import org.eclipse.passage.lic.api.tests.conditions.evaluation.ExpressionParsingServiceContractTest;
import org.eclipse.passage.lic.internal.api.conditions.evaluation.ExpressionParsingException;
import org.eclipse.passage.lic.internal.api.conditions.evaluation.ExpressionParsingService;
import org.eclipse.passage.lic.internal.api.conditions.evaluation.ParsedExpression;
import org.eclipse.passage.lic.internal.base.conditions.evaluation.AndsProtocolExpressionParseService;
import org.eclipse.passage.lic.internal.base.conditions.evaluation.SimpleMapExpression;
import org.junit.Test;

@SuppressWarnings("restriction")
public final class AndsProtocolExpressionParseServiceTest extends ExpressionParsingServiceContractTest {

@Test
public void parsesValidData() {
try {
parser().parsed("a=b"); //$NON-NLS-1$
} catch (ExpressionParsingException e) {
fail("Is not expected to fial on valid data"); //$NON-NLS-1$
}
}

@Test
public void pasingIsAccurate() throws ExpressionParsingException {
SimpleMapExpression parsed = (SimpleMapExpression) parser().parsed("k1=v1;k2=*;"); //$NON-NLS-1$
assertEquals("v1", parsed.expected("k1")); //$NON-NLS-1$//$NON-NLS-2$
assertEquals("*", parsed.expected("k2")); //$NON-NLS-1$//$NON-NLS-2$
}

@Test(expected = ExpressionParsingException.class)
public void evenSingleCorruptedSegmentFailsParsing() throws ExpressionParsingException {
parser().parsed("k1=v1;k2;k3=v3"); //$NON-NLS-1$
}

@Test(expected = ExpressionParsingException.class)
public void valueOnlySegmentIsCorrupted() throws ExpressionParsingException {
parser().parsed("k1=v1;=v2;k3=v3"); //$NON-NLS-1$
}

@Test(expected = ExpressionParsingException.class)
public void mediatorOnlySegmentIsCorrupted() throws ExpressionParsingException {
parser().parsed("k1=v1;=;k3=v3"); //$NON-NLS-1$
}

@Test
public void allowsWhiteSpaces() throws ExpressionParsingException {
SimpleMapExpression parsed = (SimpleMapExpression) parser().parsed("k 1=v 1"); //$NON-NLS-1$
assertEquals("v 1", parsed.expected("k 1")); //$NON-NLS-1$//$NON-NLS-2$
}

@Test
public void keysAndValuesAreTrimmed() throws ExpressionParsingException {
SimpleMapExpression parsed = (SimpleMapExpression) parser().parsed(" k\n= v\t"); //$NON-NLS-1$
assertEquals("v", parsed.expected("k")); //$NON-NLS-1$//$NON-NLS-2$
}

@Override
protected ExpressionParsingService parser() {
return new AndsProtocolExpressionParseService();
}

@Override
protected String validExpression() {
return "a=b;c=*;d=1 2"; //$NON-NLS-1$
}

@Override
protected Class<? extends ParsedExpression> resultType() {
return SimpleMapExpression.class;
}

}
Loading