@Nonnull
    public static <T> AggregateOperation1<T, LinTrendAccumulator, Double> linearTrend(
            @Nonnull ToLongFunctionEx<T> getXFn,
            @Nonnull ToLongFunctionEx<T> getYFn
    ) {
        checkSerializable(getXFn, "getXFn");
        checkSerializable(getYFn, "getYFn");
        return AggregateOperation
                .withCreate(LinTrendAccumulator::new)
                .andAccumulate((LinTrendAccumulator a, T item) ->
                        a.accumulate(getXFn.applyAsLong(item), getYFn.applyAsLong(item)))
                .andCombine(LinTrendAccumulator::combine)
                .andDeduct(LinTrendAccumulator::deduct)
                .andExportFinish(LinTrendAccumulator::export);
    }
@Test
    public void when_linearTrend() {
        // Given
        AggregateOperation1<Entry<Long, Long>, LinTrendAccumulator, Double> op =
                linearTrend(Entry::getKey, Entry::getValue);
        Supplier<LinTrendAccumulator> createFn = op.createFn();
        BiConsumer<? super LinTrendAccumulator, ? super Entry<Long, Long>> accFn = op.accumulateFn();
        BiConsumer<? super LinTrendAccumulator, ? super LinTrendAccumulator> combineFn = op.combineFn();
        BiConsumer<? super LinTrendAccumulator, ? super LinTrendAccumulator> deductFn = op.deductFn();
        Function<? super LinTrendAccumulator, ? extends Double> finishFn = op.finishFn();
        assertNotNull(createFn);
        assertNotNull(accFn);
        assertNotNull(combineFn);
        assertNotNull(deductFn);
        assertNotNull(finishFn);

        // When
        LinTrendAccumulator a1 = createFn.get();
        accFn.accept(a1, entry(1L, 3L));
        accFn.accept(a1, entry(2L, 5L));
        assertEquals(2.0, finishFn.apply(a1), Double.MIN_VALUE);

        LinTrendAccumulator a2 = createFn.get();
        accFn.accept(a2, entry(5L, 11L));
        accFn.accept(a2, entry(6L, 13L));
        assertEquals(2.0, finishFn.apply(a2), Double.MIN_VALUE);

        combineFn.accept(a1, a2);
        assertEquals(2.0, finishFn.apply(a1), Double.MIN_VALUE);

        deductFn.accept(a1, a2);
        assertEquals(2.0, finishFn.apply(a1), Double.MIN_VALUE);

        Double result = finishFn.apply(a1);
        assertEquals(Double.valueOf(2), result);

        // When
        LinTrendAccumulator acc = createFn.get();
        // Then
        assertTrue("NaN expected if nothing accumulated", Double.isNaN(finishFn.apply(acc)));

        // When
        accFn.accept(acc, entry(2L, 1L));
        // Then
        assertTrue("NaN expected if just single point accumulated", Double.isNaN(finishFn.apply(acc)));

        // When
        accFn.accept(acc, entry(2L, 1L));
        // Then
        assertTrue("NaN expected if all data points are equal", Double.isNaN(finishFn.apply(acc)));

        // When
        accFn.accept(acc, entry(2L, 2L));
        // Then
        assertTrue("NaN expected if all data points have same x value", Double.isNaN(finishFn.apply(acc)));
    }