3

While refactoring Rultor to use Cactoos instead of Guava, I’m having an issue with negative tests of GithubProfileTest and GithubProfileValidationTest.

After the refactor, the positive test cases pass for both mentioned test classes, but the negative test cases that expect a particular exception fail. The affected refactored code under test is GithubProfile.assets method and GithubProfile.asset method.

I refactored assets method to look like this:

 public Map<String, InputStream> assets() throws IOException {
    final XML xml = this.read();
    final List<XML> nodes = xml.nodes("/p/entry[@key='assets']/entry");
    return new MapOf<>(
        new Mapped<>(
            nodes,
            input ->
                new MapEntry<>(
                    input.xpath("@key").get(0),
                    this.asset(input.xpath("text()").get(0))
                )
        )
    );
}

On different test cases the this.asset call is expected to throw Profile.ConfigException. Instead, upon calling the assets method, the test fails with a Unable to evaluate the expression Method threw 'java.io.UncheckedIOException' exception, and the Profile.ConfigException is simply ignored/hidden.

It seems that MapOf somehow fails to evaluate, or "hides", the exception that the call to this.asset method raised, raising itself an UncheckedIOException, so I'm unable to fix this and have the Profile.ConfigException raised.

When debugging, the UncheckedIOException doesn't contain any info whatsoever of a Profile.ConfigException being raised.

Any hints on why I might be getting this behaviour or possible solutions?

Kirill
  • 7,580
  • 6
  • 44
  • 95
Filipe Freire
  • 823
  • 7
  • 21
  • The only line of code I see which can throw an `UncheckedIOException` here is your `read()` method. What does it do? – fge Sep 05 '17 at 20:15

2 Answers2

3

The reason is probably the conversion done in org.cactoos.func.UncheckedFunc while iterating to populate the map.

Since functional style programming usually does not play very well with exceptions, the API tries to avoid declaring checked exceptions. So you probably have to live with that.

aventurin
  • 2,056
  • 4
  • 26
  • 30
3

The problem is that Iterable#next() (in JDK) doesn't allow to throw checked exceptions (like Profile.ConfigException). That's why org.cactoos.iterator.Mapped catches them all and throws UncheckedIOException instead. It's unfixable, thanks to JDK design. The best you can do is good old for loop:

public Map<String, InputStream> assets() throws IOException {
  final XML xml = this.read();
  final List<XML> nodes = xml.nodes("/p/entry[@key='assets']/entry");
  final List<MapEntry> entries = new LinkedList<>();
  for (final XML node : nodes) {
    entries.add(
      new MapEntry<>(
        input.xpath("@key").get(0),
        this.asset(input.xpath("text()").get(0)) // checked exeption here
      )
    );
  }
  return new MapOf<>(entries);
}
yegor256
  • 102,010
  • 123
  • 446
  • 597