/*
 * Bach - Java Shell Builder
 * Copyright (C) 2019 Christian Stein
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package de.sormuras.bach;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;

import java.lang.module.ModuleDescriptor.Version;
import java.lang.module.ModuleFinder;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Optional;
import java.util.Set;
import java.util.spi.ToolProvider;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;

class ResolverTests {

  @Test
  void ofConstructor() {
    var v2 = Version.parse("2");
    assertABC(new Resolver(Set.of("a", "b"), Map.of("a", Set.of(), "c", Set.of(v2))));
  }

  @Test
  void ofCommandLineStrings() {
    assertABC(Resolver.of(Set.of("a", "b"), Set.of("a", "c@2")));
  }

  @Test
  void ofModuleInfoSource() {
    assertABC(Resolver.of("module a {}", "module b { requires a; requires c/*2*/; }"));
  }

  @Test
  void ofParsingSourceFiles(@TempDir Path temp) throws Exception {
    declare(temp, "a", "module a {}");
    declare(temp, "b", "module b { requires a; requires c /*2*/;}");
    assertABC(Resolver.of(Set.of(temp)));
  }

  @Test
  void ofModuleFinder(@TempDir Path temp) throws Exception {
    var a = declare(temp, "a", "module a {}");
    var b = declare(temp, "b", "module b { requires a; requires c;}");
    var c = declare(temp, "c", "module c {}");
    var javac = ToolProvider.findFirst("javac").orElseThrow();
    javac.run(System.out, System.err, a.toString());
    javac.run(System.out, System.err, "--module-version", "2", c.toString()); // c@2
    javac.run(System.out, System.err, "--module-path", temp.toString(), b.toString());
    Files.delete(temp.resolve("c/module-info.class")); // Make module "c" magically disappear...
    assertABC(Resolver.of(ModuleFinder.of(temp)));
  }

  private static Path declare(Path path, String name, String source) throws Exception {
    var directory = Files.createDirectory(path.resolve(name));
    return Files.writeString(directory.resolve("module-info.java"), source);
  }

  private static void assertABC(Resolver resolver) {
    assertEquals(Set.of("a", "b"), resolver.getDeclaredModules());
    assertEquals(Set.of("a", "c"), resolver.getRequiredModules());
    assertEquals(Optional.empty(), resolver.getRequiredVersion("a"));
    assertEquals("2", resolver.getRequiredVersion("c").orElseThrow().toString());
    var e = assertThrows(NoSuchElementException.class, () -> resolver.getRequiredVersion("x"));
    assertEquals("Module x is not mapped", e.getMessage());
  }
}

@@ -768,22 +768,141 @@
 s.assert
-Throws
+False;%0Aimport static org.junit.jupiter.api.Assertions.assertThrows;%0Aimport static org.junit.jupiter.api.Assertions.assertTrue
 ;%0A%0Aimpor
@@ -1186,17 +1186,16 @@
 ovider;%0A
-%0A
 import o
@@ -1588,16 +1588,23 @@
 foSource
+Strings
 () %7B%0A   
@@ -1714,15 +1714,18 @@
 d of
-Parsing
+ModuleInfo
 Sour
@@ -2545,16 +2545,16 @@
 pear...%0A
-
     asse
@@ -2593,32 +2593,377 @@
 f(temp)));%0A  %7D%0A%0A
+  @Test%0A  void ofSystem() %7B%0A    var system = Resolver.of(ModuleFinder.ofSystem());%0A    assertTrue(system.getDeclaredModules().contains(%22java.base%22));%0A    assertFalse(system.getRequiredModules().contains(%22java.base%22)); // mandated requires are ignored%0A    assertTrue(system.getDeclaredModules().size() %3E system.getRequiredModules().size());%0A  %7D%0A%0A
   private static

Add test for system modules