@Override public void afterUpdate(M model, E event, Next<M, F> result) { if (result.hasModel()) { LOGGER.debug(LOGGING_PREFIX + "Model updated: {}", loggingTag, result.modelUnsafe()); } for (F effect : result.effects()) { LOGGER.debug(LOGGING_PREFIX + "Effect dispatched: {}", loggingTag, effect); } }
@Nonnull @Override public Next<M, Object> update(M model, E event) { return Next.next(update.apply(model, event)); } },
@Test public void canMergeInnerEffects() throws Exception { Next<String, String> outerNext = Next.next("m", effects("f1", "f2")); Next<?, String> innerNext = dispatch(effects("f2", "f3")); Next<String, String> merged = Next.next( outerNext.modelOrElse("fail"), unionSets(innerNext.effects(), outerNext.effects())); assertEquals(Next.next("m", effects("f1", "f2", "f3")), merged); }
/** * Get the model of this Next. This version is unsafe - if this next doesn't have a model, calling * this method will cause an exception to be thrown. * * <p>In almost all cases you should use {@link #modelOrElse} or {@link #ifHasModel} instead. * * @throws NoSuchElementException if this Next has no model */ @Nonnull public M modelUnsafe() { if (!hasModel()) { throw new NoSuchElementException("there is no model in this Next<>"); } // we know model is never null here since we just checked it. //noinspection ConstantConditions return model(); }
/** * Try to get the model from this Next, with a fallback if there isn't one. * * @param fallbackModel the default model to use if the Next doesn't have a model */ @Nonnull public M modelOrElse(M fallbackModel) { checkNotNull(fallbackModel); if (hasModel()) { return modelUnsafe(); } else { return fallbackModel; } }
@Test public void nextNoEffectsOnlyHasModel() throws Exception { Next<String, String> next = Next.next("foo"); assertTrue(next.hasModel()); assertFalse(next.hasEffects()); }
@Nonnull @Override public Next<M, F> handleInnerEffects(M model, boolean modelUpdated, Set<FI> innerEffects) { if (innerEffects.isEmpty()) { return modelUpdated ? Next.<M, F>next(model) : Next.<M, F>noChange(); } Set<F> effects = new HashSet<>(); for (FI innerEffect : innerEffects) { F outerEffect = checkNotNull(f).apply(innerEffect); effects.add(checkNotNull(outerEffect)); } if (modelUpdated) { return Next.next(model, effects); } else { return Next.dispatch(effects); } } };
@Test public void canMergeInnerEffectsAndModel() throws Exception { Set<String> effects = setOf("f1", "f2"); Next<Integer, String> innerNext = Next.next(1, effects("f2", "f3")); Next<String, String> merged = Next.next("m" + innerNext.modelOrElse(0), unionSets(effects, innerNext.effects())); assertEquals(Next.next("m1", effects("f1", "f2", "f3")), merged); }
@Test public void testEquals() throws Exception { Next<String, String> m1 = new AutoValue_Next<>("hi", ImmutableUtil.<String>emptySet()); Next<String, String> m2 = Next.next("hi"); Next<String, String> m3 = Next.next("hi", ImmutableUtil.<String>emptySet()); Next<String, String> n2 = Next.next("hi", effects("a", "b")); Next<String, String> n3 = Next.next("hi", effects("b", "a")); Next<String, String> n4 = Next.next("hi", ImmutableUtil.setOf("b", "a")); Next<String, String> o2 = Next.next("hi", effects("a", "c", "b")); Next<String, String> o3 = Next.next("hi", effects("b", "a", "c")); Next<String, String> o4 = Next.next("hi", ImmutableUtil.setOf("c", "b", "a")); Next<String, String> p2 = Next.dispatch(effects("a", "c", "b")); Next<String, String> p3 = Next.dispatch(effects("b", "a", "c")); Next<String, String> p4 = Next.dispatch(ImmutableUtil.setOf("c", "b", "a")); Next<String, String> q2 = Next.next("hey"); Next<String, String> q3 = Next.next("hey", Collections.<String>emptySet()); Next<String, String> r2 = Next.next("hey", effects("a", "b")); Next<String, String> s2 = Next.next("hey", effects("a", "b", "c"));
@Test public void nextNoopHasNoModelAndNoEffects() throws Exception { Next<String, String> next = noChange(); assertFalse(next.hasModel()); assertFalse(next.hasEffects()); }
@Test public void nextEffectsOnlyHasEffects() throws Exception { Next<String, String> next = dispatch(effects("foo")); assertFalse(next.hasModel()); assertTrue(next.hasEffects()); }
@SuppressWarnings("unused") private Next<?, Number> canInferFromVarargOnlyEffects() { return dispatch(effects((short) 1, 2, (long) 3)); }
synchronized void update(E event) { if (!initialised) { eventsReceivedBeforeInit.add(event); return; } Next<M, F> next = store.update(event); next.ifHasModel( new Consumer<M>() { @Override public void accept(M model) { dispatchModel(model); } }); dispatchEffects(next.effects()); }
@Override protected boolean matchesSafely(Next<M, F> item, Description mismatchDescription) { if (!item.hasEffects()) { mismatchDescription.appendText("no effects"); return false; } else if (!matcher.matches(item.effects())) { mismatchDescription.appendText("bad effects: "); matcher.describeMismatch(item.effects(), mismatchDescription); return false; } else { mismatchDescription.appendText("has effects: "); matcher.describeMismatch(item.effects(), mismatchDescription); return true; } }
@Test public void testHasModelSpecificButMissing() throws Exception { next = noChange(); matcher = hasModel(equalTo("a")); assertFalse(matcher.matches(next)); matcher.describeMismatch(next, desc); assertEquals("no model", desc.toString()); }
@Override protected boolean matchesSafely(Next<M, F> item, Description mismatchDescription) { if (item.hasModel()) { mismatchDescription.appendText("has a model"); return false; } else { mismatchDescription.appendText("no model"); return true; } }
/** Check if this Next contains effects. */ public final boolean hasEffects() { return !effects().isEmpty(); }
@Nonnull synchronized Next<M, F> update(E event) { Next<M, F> next = update.update(currentModel, checkNotNull(event)); currentModel = next.modelOrElse(currentModel); return next; } }