public final class ProcessorChainTest { private static final MessageBundle BUNDLE = MessageBundles.getBundle(JsonSchemaCoreMessageBundle.class); @Test public void cannotInitiateWithNullProcessor() { try { ProcessorChain.startWith(null); fail("No exception thrown!!"); } catch (NullPointerException e) { assertEquals(e.getMessage(), BUNDLE.getMessage("processing.nullProcessor")); } } @Test public void cannotChainWithNullProcessor() { @SuppressWarnings("unchecked") final Processor<MessageProvider, MessageProvider> p = mock(Processor.class); try { ProcessorChain.startWith(p).chainWith(null); fail("No exception thrown!!"); } catch (NullPointerException e) { assertEquals(e.getMessage(), BUNDLE.getMessage("processing.nullProcessor")); } } @Test public void failingOnErrorExitsEarly() throws ProcessingException { @SuppressWarnings("unchecked") final Processor<MessageProvider, MessageProvider> p1 = mock(Processor.class); @SuppressWarnings("unchecked") final Processor<MessageProvider, MessageProvider> p2 = mock(Processor.class); final Processor<MessageProvider, MessageProvider> processor = ProcessorChain.startWith(p1).failOnError().chainWith(p2).getProcessor(); final MessageProvider input = mock(MessageProvider.class); final ProcessingReport report = new DummyReport(LogLevel.ERROR); try { processor.process(report, input); fail("No exception thrown!!"); } catch (ProcessingException e) { assertMessage(e.getProcessingMessage()) .hasMessage(BUNDLE.getMessage("processing.chainStopped")); } verify(p1).process(same(report), any(MessageProvider.class)); verify(p2, never()).process(any(ProcessingReport.class), any(MessageProvider.class)); } @Test public void noFailureDoesNotTriggerEarlyExit() throws ProcessingException { @SuppressWarnings("unchecked") final Processor<MessageProvider, MessageProvider> p1 = mock(Processor.class); @SuppressWarnings("unchecked") final Processor<MessageProvider, MessageProvider> p2 = mock(Processor.class); final Processor<MessageProvider, MessageProvider> processor = ProcessorChain.startWith(p1).failOnError().chainWith(p2).getProcessor(); final MessageProvider input = mock(MessageProvider.class); final ProcessingReport report = new DummyReport(LogLevel.DEBUG); processor.process(report, input); verify(p1).process(same(report), any(MessageProvider.class)); verify(p2).process(same(report), any(MessageProvider.class)); } private static final class DummyReport extends AbstractProcessingReport { private DummyReport(final LogLevel currentLevel) throws ProcessingException { dispatch(new ProcessingMessage().setLogLevel(currentLevel)); } @Override public void log(final LogLevel level, final ProcessingMessage message) {} } }
public final class NotKeywordTest { private static final MessageBundle BUNDLE = MessageBundles.getBundle(JsonSchemaValidationBundle.class); private static final JsonNodeFactory FACTORY = JacksonUtils.nodeFactory(); private static final ProcessingMessage MSG = new ProcessingMessage(); private final KeywordValidator validator; private Processor<FullData, FullData> processor; private FullData data; private ProcessingReport report; public NotKeywordTest() throws IllegalAccessException, InvocationTargetException, InstantiationException { final Constructor<? extends KeywordValidator> constructor = DraftV4ValidatorDictionary.get().entries().get("not"); validator = constructor == null ? null : constructor.newInstance(FACTORY.nullNode()); } @BeforeMethod public void initEnvironment() { if (validator == null) return; final ObjectNode schema = FACTORY.objectNode(); schema.put("not", FACTORY.objectNode()); final SchemaTree tree = new CanonicalSchemaTree(schema); final JsonTree instance = new SimpleJsonTree(FACTORY.nullNode()); data = new FullData(tree, instance); report = mock(ProcessingReport.class); when(report.getLogLevel()).thenReturn(LogLevel.DEBUG); } @Test public void keywordExists() { assertNotNull(validator, "no support for not??"); } @Test(dependsOnMethods = "keywordExists") public void exceptionIsCorrectlyThrown() { processor = new DummyProcessor(WantedState.EX); try { validator.validate(processor, report, BUNDLE, data); fail("No exception thrown??"); } catch (ProcessingException ignored) { } } @Test(dependsOnMethods = "keywordExists") public void successfulSubSchemaLeadsToFailure() throws ProcessingException { processor = new DummyProcessor(WantedState.OK); final ArgumentCaptor<ProcessingMessage> captor = ArgumentCaptor.forClass(ProcessingMessage.class); validator.validate(processor, report, BUNDLE, data); verify(report).error(captor.capture()); final ProcessingMessage message = captor.getValue(); assertMessage(message).isValidationError("not", BUNDLE.getMessage("err.draftv4.not.fail")); } @Test(dependsOnMethods = "keywordExists") public void failingSubSchemaLeadsToSuccess() throws ProcessingException { processor = new DummyProcessor(WantedState.KO); validator.validate(processor, report, BUNDLE, data); verify(report, never()).error(anyMessage()); } private enum WantedState { OK { @Override void doIt(final ProcessingReport report) throws ProcessingException {} }, KO { @Override void doIt(final ProcessingReport report) throws ProcessingException { report.error(MSG); } }, EX { @Override void doIt(final ProcessingReport report) throws ProcessingException { throw new ProcessingException(); } }; abstract void doIt(final ProcessingReport report) throws ProcessingException; } private static final class DummyProcessor implements Processor<FullData, FullData> { private static final JsonPointer PTR = JsonPointer.of("not"); private final WantedState wanted; private DummyProcessor(final WantedState wanted) { this.wanted = wanted; } @Override public FullData process(final ProcessingReport report, final FullData input) throws ProcessingException { assertEquals(input.getSchema().getPointer(), PTR); wanted.doIt(report); return input; } } }
@Test public abstract class AbstractKeywordValidatorTest { private static final MessageBundle BUNDLE = MessageBundles.getBundle(JsonSchemaValidationBundle.class); private final String keyword; private final KeywordValidatorFactory factory; private final JsonNode testNode; protected AbstractKeywordValidatorTest( final Dictionary<KeywordValidatorFactory> dict, final String prefix, final String keyword) throws IOException { this.keyword = keyword; factory = dict.entries().get(keyword); final String resourceName = String.format("/keyword/validators/%s/%s.json", prefix, keyword); testNode = JsonLoader.fromResource(resourceName); } @Test public final void keywordExists() { assertNotNull(factory, "no support for " + keyword + "??"); } @DataProvider protected final Iterator<Object[]> getValueTests() { final List<Object[]> list = Lists.newArrayList(); String msg; JsonNode msgNode, msgData, msgParams; for (final JsonNode node : testNode) { msgNode = node.get("message"); msgData = node.get("msgData"); msgParams = node.get("msgParams"); msg = msgNode == null ? null : buildMessage(msgNode.textValue(), msgParams, msgData); list.add( new Object[] { node.get("digest"), node.get("data"), msg, node.get("valid").booleanValue(), msgData }); } return list.iterator(); } // Unfortunately, the suppress warning annotation is needed @Test(dataProvider = "getValueTests", dependsOnMethods = "keywordExists") public final void instancesAreValidatedCorrectly( final JsonNode digest, final JsonNode node, final String msg, final boolean valid, final ObjectNode msgData) throws IllegalAccessException, InvocationTargetException, InstantiationException, ProcessingException { // FIXME: dummy, but we have no choice final SchemaTree tree = new CanonicalSchemaTree(SchemaKey.anonymousKey(), digest); final JsonTree instance = new SimpleJsonTree(node); final FullData data = new FullData(tree, instance); final ProcessingReport report = mock(ProcessingReport.class); @SuppressWarnings("unchecked") final Processor<FullData, FullData> processor = mock(Processor.class); final KeywordValidator validator = factory.getKeywordValidator(digest); validator.validate(processor, report, BUNDLE, data); if (valid) { verify(report, never()).error(anyMessage()); return; } final ArgumentCaptor<ProcessingMessage> captor = ArgumentCaptor.forClass(ProcessingMessage.class); verify(report).error(captor.capture()); final ProcessingMessage message = captor.getValue(); assertMessage(message).isValidationError(keyword, msg).hasContents(msgData); } private static String buildMessage(final String key, final JsonNode params, final JsonNode data) { final ProcessingMessage message = new ProcessingMessage().setMessage(BUNDLE.getMessage(key)); if (params != null) { String name; JsonNode value; for (final JsonNode node : params) { name = node.textValue(); value = data.get(name); message.putArgument(name, valueToArgument(value)); } } return message.getMessage(); } private static Object valueToArgument(final JsonNode value) { final NodeType type = NodeType.getNodeType(value); switch (type) { case STRING: return value.textValue(); case INTEGER: return value.bigIntegerValue(); case NUMBER: case NULL: case OBJECT: case ARRAY: return value; case BOOLEAN: return value.booleanValue(); // case ARRAY: // final List<Object> list = Lists.newArrayList(); // for (final JsonNode element: value) // list.add(valueToArgument(element)); // return list; default: throw new UnsupportedOperationException(); } } }