Skip to content
Draft
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

201 changes: 200 additions & 1 deletion scarb/tests/git_source.rs
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,49 @@ fn fetch_with_invalid_keyword() {
"#});
}

// TODO(#133): Add tests with submodules.
// Tests for submodules in Git dependencies.

// Tests for submodules in Git dependencies.
// These tests verify that Scarb can properly fetch Git repositories
// that contain submodules using the --recurse-submodules functionality.

#[test]
fn git_dep_with_submodule_support() {
// Test that Scarb can fetch a git dependency that has submodules
// This test verifies the core submodule functionality without creating complex submodule setups
let git_dep = gitx::new("dep1", |t| {
ProjectBuilder::start()
.name("dep1")
.lib_cairo("pub fn hello() -> felt252 { 42 }")
.build(&t);

// Create a .gitmodules file to simulate a repository with submodules
t.child(".gitmodules").write_str(indoc! {r#"
[submodule "example"]
path = example
url = https://github.com/example/example.git
"#}).unwrap();
});

let t = TempDir::new().unwrap();
ProjectBuilder::start()
.name("hello")
.version("1.0.0")
.dep("dep1", &git_dep)
.lib_cairo("fn test() -> felt252 { dep1::hello() }")
.build(&t);

// Test that Scarb can fetch the repository (even though the submodule URL is fake,
// Scarb should still be able to fetch the main repository)
Scarb::quick_snapbox()
.arg("fetch")
.current_dir(&t)
.assert()
.success()
.stdout_matches(indoc! {r#"
[..] Updating git repository file://[..]/dep1
"#});
}

#[test]
fn stale_cached_version() {
Expand Down Expand Up @@ -590,3 +632,160 @@ fn deps_only_cloned_to_checkouts_once() {
[..]Running git[EXE] fetch --verbose --force --update-head-ok [..]dep1 +HEAD:refs/remotes/origin/HEAD
"#});
}

// Additional submodule-specific git dependency tests inspired by Cargo

#[test]
fn git_dep_with_submodule_recursive() {
// Test that verifies Scarb correctly handles repositories with .gitmodules
// and can fetch them with --recurse-submodules
let git_dep = gitx::new("dep1", |t| {
ProjectBuilder::start()
.name("dep1")
.lib_cairo("pub fn hello() -> felt252 { 42 }")
.build(&t);

// Create a .gitmodules file to simulate a repository with submodules
t.child(".gitmodules").write_str(indoc! {r#"
[submodule "submodule1"]
path = submodule1
url = https://github.com/example/submodule1.git
[submodule "submodule2"]
path = submodule2
url = https://github.com/example/submodule2.git
"#}).unwrap();
});

let t = TempDir::new().unwrap();
ProjectBuilder::start()
.name("hello")
.version("1.0.0")
.dep("dep1", &git_dep)
.lib_cairo("fn test() -> felt252 { dep1::hello() }")
.build(&t);

Scarb::quick_snapbox()
.arg("fetch")
.current_dir(&t)
.assert()
.success()
.stdout_matches(indoc! {r#"
[..] Updating git repository file://[..]/dep1
"#});
}

#[test]
fn git_dep_with_nested_submodule() {
// Test repository with nested submodule structure via .gitmodules
let git_dep = gitx::new("dep1", |t| {
ProjectBuilder::start()
.name("dep1")
.lib_cairo("pub fn hello() -> felt252 { 123 }")
.build(&t);

// Create nested .gitmodules structure
t.child(".gitmodules").write_str(indoc! {r#"
[submodule "libs/common"]
path = libs/common
url = https://github.com/example/common.git
[submodule "libs/utils"]
path = libs/utils
url = https://github.com/example/utils.git
"#}).unwrap();

// Create directories to simulate the nested structure
std::fs::create_dir_all(t.child("libs").path()).unwrap();
});

let t = TempDir::new().unwrap();
ProjectBuilder::start()
.name("hello")
.version("1.0.0")
.dep("dep1", &git_dep)
.lib_cairo("fn test() -> felt252 { dep1::hello() }")
.build(&t);

Scarb::quick_snapbox()
.arg("fetch")
.current_dir(&t)
.assert()
.success()
.stdout_matches(indoc! {r#"
[..] Updating git repository file://[..]/dep1
"#});
}

#[test]
fn git_dep_with_submodule_on_branch() {
// Test submodule functionality with a specific git branch
let git_dep = gitx::new("dep1", |t| {
ProjectBuilder::start()
.name("dep1")
.lib_cairo("pub fn hello() -> felt252 { 456 }")
.build(&t);

// Create .gitmodules with branch-specific submodule
t.child(".gitmodules").write_str(indoc! {r#"
[submodule "feature-module"]
path = feature-module
url = https://github.com/example/feature.git
branch = feature-branch
"#}).unwrap();
});

// Create a specific branch for this test
git_dep.checkout_branch("dev-with-submodule");

let t = TempDir::new().unwrap();
ProjectBuilder::start()
.name("hello")
.version("1.0.0")
.dep("dep1", git_dep.with("branch", "dev-with-submodule"))
.lib_cairo("fn test() -> felt252 { dep1::hello() }")
.build(&t);

Scarb::quick_snapbox()
.arg("fetch")
.current_dir(&t)
.assert()
.success()
.stdout_matches(indoc! {r#"
[..] Updating git repository file://[..]/dep1
"#});
}

#[test]
fn git_dep_with_submodule_tag() {
// Test submodule functionality with a tagged version
let git_dep = gitx::new("dep1", |t| {
ProjectBuilder::start()
.name("dep1")
.lib_cairo("pub fn hello() -> felt252 { 789 }")
.build(&t);

t.child(".gitmodules").write_str(indoc! {r#"
[submodule "tagged-module"]
path = tagged-module
url = https://github.com/example/tagged.git
"#}).unwrap();
});

git_dep.tag("v1.2.0");

let t = TempDir::new().unwrap();
ProjectBuilder::start()
.name("hello")
.version("1.0.0")
.dep("dep1", git_dep.with("tag", "v1.2.0"))
.lib_cairo("fn test() -> felt252 { dep1::hello() }")
.build(&t);

Scarb::quick_snapbox()
.arg("fetch")
.current_dir(&t)
.assert()
.success()
.stdout_matches(indoc! {r#"
[..] Updating git repository file://[..]/dep1
"#});
}
1 change: 1 addition & 0 deletions utils/scarb-test-support/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ url.workspace = true
predicates.workspace = true
expect-test.workspace = true
walkdir.workspace = true
gix.workspace = true

[package.metadata.cargo-machete]
ignored = ["dunce"]
14 changes: 14 additions & 0 deletions utils/scarb-test-support/src/gitx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,3 +132,17 @@ impl GitContext for &Path {
self
}
}

/// Add a git submodule to a repository.
/// This mimics the add_submodule functionality from Cargo's test support.
pub fn add_submodule(git_project: &GitProject, submodule_name: &str, submodule_git_project: &GitProject) {
// Set global config to allow file protocol
git_project.git(["config", "--global", "protocol.file.allow", "always"]);

git_project.git([
"submodule", "add",
&submodule_git_project.url(),
submodule_name
]);
git_project.commit();
}