use super::*;

#[test]
fn import_succeeds() {
  Test::new()
    .tree(tree! {
      "import.justfile": "
        b:
          @echo B
      ",
    })
    .justfile(
      "
        import './import.justfile'

        a: b
          @echo A
      ",
    )
    .arg("a")
    .stdout("B\nA\n")
    .run();
}

#[test]
fn missing_import_file_error() {
  Test::new()
    .justfile(
      "
        import './import.justfile'

        a:
          @echo A
      ",
    )
    .arg("a")
    .status(EXIT_FAILURE)
    .stderr(
      "
      error: Could not find source file for import.
       ——▶ justfile:1:8
        │
      1 │ import './import.justfile'
        │        ^^^^^^^^^^^^^^^^^^^
      ",
    )
    .run();
}

#[test]
fn missing_optional_imports_are_ignored() {
  Test::new()
    .justfile(
      "
        import? './import.justfile'

        a:
          @echo A
      ",
    )
    .arg("a")
    .stdout("A\n")
    .run();
}

#[test]
fn trailing_spaces_after_import_are_ignored() {
  Test::new()
    .tree(tree! {
      "import.justfile": "",
    })
    .justfile(
      "
      import './import.justfile'\x20
      a:
        @echo A
    ",
    )
    .stdout("A\n")
    .run();
}

#[test]
fn import_after_recipe() {
  Test::new()
    .tree(tree! {
      "import.justfile": "
        a:
          @echo A
      ",
    })
    .justfile(
      "
      b: a
      import './import.justfile'
      ",
    )
    .stdout("A\n")
    .run();
}

#[test]
fn circular_import() {
  Test::new()
    .justfile("import 'a'")
    .tree(tree! {
      a: "import 'b'",
      b: "import 'a'",
    })
    .status(EXIT_FAILURE)
    .stderr_regex(path_for_regex(
      "error: Import `.*/a` in `.*/b` is circular\n",
    ))
    .run();
}

#[test]
fn import_recipes_are_not_default() {
  Test::new()
    .tree(tree! {
      "import.justfile": "bar:",
    })
    .justfile("import './import.justfile'")
    .status(EXIT_FAILURE)
    .stderr("error: Justfile contains no default recipe.\n")
    .run();
}

#[test]
fn listed_recipes_in_imports_are_in_load_order() {
  Test::new()
    .justfile(
      "
      import './import.justfile'
      foo:
    ",
    )
    .write("import.justfile", "bar:")
    .args(["--list", "--unsorted"])
    .stdout(
      "
      Available recipes:
          foo
          bar
    ",
    )
    .run();
}

#[test]
fn include_error() {
  Test::new()
    .justfile("!include foo")
    .status(EXIT_FAILURE)
    .stderr(
      "
      error: The `!include` directive has been stabilized as `import`
       ——▶ justfile:1:1
        │
      1 │ !include foo
        │ ^
      ",
    )
    .run();
}

#[test]
fn recipes_in_import_are_overridden_by_recipes_in_parent() {
  Test::new()
    .tree(tree! {
      "import.justfile": "
        a:
          @echo IMPORT
      ",
    })
    .justfile(
      "
        a:
          @echo ROOT

        import './import.justfile'

        set allow-duplicate-recipes
      ",
    )
    .arg("a")
    .stdout("ROOT\n")
    .run();
}

#[test]
fn variables_in_import_are_overridden_by_variables_in_parent() {
  Test::new()
    .tree(tree! {
      "import.justfile": "
    f := 'foo'
    ",
    })
    .justfile(
      "
      f := 'bar'

      import './import.justfile'

      set allow-duplicate-variables

      a:
        @echo {{f}}
    ",
    )
    .arg("a")
    .stdout("bar\n")
    .run();
}

#[cfg(not(windows))]
#[test]
fn import_paths_beginning_with_tilde_are_expanded_to_homdir() {
  Test::new()
    .write("foobar/mod.just", "foo:\n @echo FOOBAR")
    .justfile(
      "
        import '~/mod.just'
      ",
    )
    .arg("foo")
    .stdout("FOOBAR\n")
    .env("HOME", "foobar")
    .run();
}

#[test]
fn imports_dump_correctly() {
  Test::new()
    .write("import.justfile", "")
    .justfile(
      "
        import './import.justfile'
      ",
    )
    .arg("--dump")
    .stdout("import './import.justfile'\n")
    .run();
}

#[test]
fn optional_imports_dump_correctly() {
  Test::new()
    .write("import.justfile", "")
    .justfile(
      "
        import? './import.justfile'
      ",
    )
    .arg("--dump")
    .stdout("import? './import.justfile'\n")
    .run();
}

#[test]
fn imports_in_root_run_in_justfile_directory() {
  Test::new()
    .write("foo/import.justfile", "bar:\n @cat baz")
    .write("baz", "BAZ")
    .justfile(
      "
        import 'foo/import.justfile'
      ",
    )
    .arg("bar")
    .stdout("BAZ")
    .run();
}

#[test]
fn imports_in_submodules_run_in_submodule_directory() {
  Test::new()
    .justfile("mod foo")
    .write("foo/mod.just", "import 'import.just'")
    .write("foo/import.just", "bar:\n @cat baz")
    .write("foo/baz", "BAZ")
    .arg("foo")
    .arg("bar")
    .stdout("BAZ")
    .run();
}

#[test]
fn nested_import_paths_are_relative_to_containing_submodule() {
  Test::new()
    .justfile("import 'foo/import.just'")
    .write("foo/import.just", "import 'bar.just'")
    .write("foo/bar.just", "bar:\n @echo BAR")
    .arg("bar")
    .stdout("BAR\n")
    .run();
}

#[test]
fn recipes_in_nested_imports_run_in_parent_module() {
  Test::new()
    .justfile("import 'foo/import.just'")
    .write("foo/import.just", "import 'bar/import.just'")
    .write("foo/bar/import.just", "bar:\n @cat baz")
    .write("baz", "BAZ")
    .arg("bar")
    .stdout("BAZ")
    .run();
}

#[test]
fn shebang_recipes_in_imports_in_root_run_in_justfile_directory() {
  Test::new()
    .write(
      "foo/import.justfile",
      "bar:\n #!/usr/bin/env bash\n cat baz",
    )
    .write("baz", "BAZ")
    .justfile(
      "
        import 'foo/import.justfile'
      ",
    )
    .arg("bar")
    .stdout("BAZ")
    .run();
}

#[test]
fn recipes_imported_in_root_run_in_command_line_provided_working_directory() {
  Test::new()
    .write("subdir/b.justfile", "@b:\n  cat baz")
    .write("subdir/a.justfile", "import 'b.justfile'\n@a: b\n  cat baz")
    .write("baz", "BAZ")
    .args([
      "--working-directory",
      ".",
      "--justfile",
      "subdir/a.justfile",
    ])
    .stdout("BAZBAZ")
    .run();
}

#[test]
fn reused_import_are_allowed() {
  Test::new()
    .justfile(
      "
      import 'a'
      import 'b'

      bar:
    ",
    )
    .tree(tree! {
      a: "import 'c'",
      b: "import 'c'",
      c: "",
    })
    .run();
}

#[test]
fn multiply_imported_items_do_not_conflict() {
  Test::new()
    .justfile(
      "
      import 'a.just'
      import 'a.just'
      foo: bar
    ",
    )
    .write(
      "a.just",
      "
x := 'y'

@bar:
  echo hello
",
    )
    .stdout("hello\n")
    .run();
}

#[test]
fn nested_multiply_imported_items_do_not_conflict() {
  Test::new()
    .justfile(
      "
      import 'a.just'
      import 'b.just'
      foo: bar
    ",
    )
    .write("a.just", "import 'c.just'")
    .write("b.just", "import 'c.just'")
    .write(
      "c.just",
      "
x := 'y'

@bar:
  echo hello
",
    )
    .stdout("hello\n")
    .run();
}
