dtonhofer

dtonhofer

Functional Programming in Java, Second Edition: Functional Programming in Java, Second Edition: JUnit code improvements for Chapter 11, pages 185 ff “Refactoring Unbounded Loops”

The same remarks apply as for “Refactoring the Traditional for Loop”

  • No init()
  • Negative tests which apply for input less than 1900, resulting in exceptions.

but we cannot implement a common interface as the method parameters change. So we wrap the new class into a class that obeys the old interface, which agains llaows us to use the same test code to test both odl and new classes.

There is also a little tweak to the semantics of the case where 1900 is already rejected - instead of returning 0, we throw. Because there basically is no result in that case.

package chapter11;

import org.junit.jupiter.api.Test;

import java.time.Year;
import java.util.function.Predicate;
import java.util.stream.IntStream;

import static org.junit.jupiter.api.Assertions.*;

public class UnboundedLoopTest {

    interface Continue {

        boolean check(int year);

    }

    interface WithContinue {

        int countFrom1900(final Continue shouldContinue);

    }

    static class LeapYearsUnboundedBefore implements WithContinue {

        public int countFrom1900(final Continue shouldContinue) {
            if (!shouldContinue.check(1900)) {
                throw new IllegalArgumentException("Cannot 'continue' right at the start!'");
            }
            int count = 0;
            for (int year = 1900; ; year += 4) {
                if (!shouldContinue.check(year)) {
                    break;
                }
                if (Year.isLeap(year)) {
                    count++;
                }
            }
            return count;
        }
    }

    // Does NOT implement WithContinue!!

    static class LeapYearsUnboundedAfter {

        public int countFrom1900(final Predicate<Integer> shouldContinue) {
            if (!shouldContinue.test(1900)) {
                throw new IllegalArgumentException("Cannot 'continue' right at the start!'");
            }
            return (int) IntStream.iterate(1900, year -> year + 4)
                    .takeWhile(shouldContinue::test)
                    .filter(Year::isLeap)
                    .count();
        }
    }

    static class LeapYearsUnboundedAfterWrapped implements WithContinue {

        private final LeapYearsUnboundedAfter ly;

        public LeapYearsUnboundedAfterWrapped(LeapYearsUnboundedAfter ly) {
            this.ly = ly;
        }

        public int countFrom1900(final Continue shouldContinue) {
            return ly.countFrom1900(year -> shouldContinue.check(year));
        }

    }

    // One should maybe have a separate method to test the throws
    
    private static void commonLeapYearsTests(final WithContinue withContinue) {
        assertAll(
                () -> assertEquals(0, withContinue.countFrom1900(year -> year <= 1900)),
                () -> assertEquals(25, withContinue.countFrom1900(year -> year <= 2000)),
                () -> assertEquals(27, withContinue.countFrom1900(year -> year <= 2010)),
                () -> assertEquals(31, withContinue.countFrom1900(year -> year <= 2025)),
                () -> assertEquals(49, withContinue.countFrom1900(year -> year <= 2100)),
                () -> assertEquals(267, withContinue.countFrom1900(year -> year <= 3000)),
                () -> assertThrows(IllegalArgumentException.class, () ->
                        withContinue.countFrom1900(year -> year < 1800)
                ),
                () -> assertThrows(IllegalArgumentException.class, () ->
                        withContinue.countFrom1900(year -> year < 1900)
                )
        );
    }

    @Test
    void leapYearCountBefore() {
        commonLeapYearsTests(new LeapYearsUnboundedBefore());
    }

    @Test
    void leapYearCountAfter() {
        commonLeapYearsTests(new LeapYearsUnboundedAfterWrapped(new LeapYearsUnboundedAfter()));
    }

}

Where Next?

Popular Pragmatic Bookshelf topics Top

iPaul
page 37 ANTLRInputStream input = new ANTLRInputStream(is); as of ANTLR 4 .8 should be: CharStream stream = CharStreams.fromStream(i...
New
mikecargal
Title: Hands-On Rust (Chapter 11: prefab) Just played a couple of amulet-less games. With a bit of debugging, I believe that your can_p...
New
JohnS
I can’t setup the Rails source code. This happens in a working directory containing multiple (postgres) Rails apps. With: ruby-3.0.0 s...
New
joepstender
The generated iex result below should list products instead of product for the metadata. (page 67) iex&gt; product = %Product{} %Pento....
New
jeremyhuiskamp
Title: Web Development with Clojure, Third Edition, vB17.0 (p9) The create table guestbook syntax suggested doesn’t seem to be accepted ...
New
brunogirin
When I run the coverage example to report on missing lines, I get: pytest --cov=cards --report=term-missing ch7 ERROR: usage: pytest [op...
New
oaklandgit
Hi, I completed chapter 6 but am getting the following error when running: thread 'main' panicked at 'Failed to load texture: IoError(O...
New
taguniversalmachine
Hi, I am getting an error I cannot figure out on my test. I have what I think is the exact code from the book, other than I changed “us...
New
redconfetti
Docker-Machine became part of the Docker Toolbox, which was deprecated in 2020, long after Docker Desktop supported Docker Engine nativel...
New
roadbike
From page 13: On Python 3.7, you can install the libraries with pip by running these commands inside a Python venv using Visual Studio ...
New

Other popular topics Top

PragmaticBookshelf
Free and open source software is the default choice for the technologies that run our world, and it’s built and maintained by people like...
New
DevotionGeo
I know that these benchmarks might not be the exact picture of real-world scenario, but still I expect a Rust web framework performing a ...
New
AstonJ
Curious to know which languages and frameworks you’re all thinking about learning next :upside_down_face: Perhaps if there’s enough peop...
New
AstonJ
This looks like a stunning keycap set :orange_heart: A LEGENDARY KEYBOARD LIVES ON When you bought an Apple Macintosh computer in the e...
New
PragmaticBookshelf
Learn different ways of writing concurrent code in Elixir and increase your application's performance, without sacrificing scalability or...
New
PragmaticBookshelf
Author Spotlight Jamis Buck @jamis This month, we have the pleasure of spotlighting author Jamis Buck, who has written Mazes for Prog...
New
PragmaticBookshelf
Author Spotlight: Peter Ullrich @PJUllrich Data is at the core of every business, but it is useless if nobody can access and analyze ...
New
New
PragmaticBookshelf
Explore the power of Ash Framework by modeling and building the domain for a real-world web application. Rebecca Le @sevenseacat and ...
New
mindriot
Ok, well here are some thoughts and opinions on some of the ergonomic keyboards I have, I guess like mini review of each that I use enoug...
New

Latest in Functional Programming in Java, Second Edition

Functional Programming in Java, Second Edition Portal

Sub Categories: