Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,31 @@ jobs:
components: rustfmt
- run: cargo fmt --all -- --check

coverage:
name: Coverage
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
Comment thread
coderabbitai[bot] marked this conversation as resolved.
- uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 # stable
with:
toolchain: stable
components: llvm-tools-preview
- uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
with:
save-if: ${{ github.event_name == 'push' }}
- uses: taiki-e/install-action@7f4eb899022d8fe70b20c4f3de697aa85c309026 # v2.85.11
with:
tool: cargo-llvm-cov
# Informational only: no --fail-under-lines, so coverage can never fail the build.
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
- name: Run coverage
run: |
{
echo "### Coverage summary"
echo '```'
cargo llvm-cov --workspace --summary-only
Comment thread
tonythethompson marked this conversation as resolved.
Outdated
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
echo '```'
Comment thread
qodo-code-review[bot] marked this conversation as resolved.
} >> "$GITHUB_STEP_SUMMARY"

roadmap-drift:
name: Roadmap drift
runs-on: ubuntu-latest
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,6 @@ desktop.ini
# Python
__pycache__/
*.py[cod]

# Coverage
*.profraw
2 changes: 2 additions & 0 deletions src/cmd/doctor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1857,6 +1857,7 @@ mod tests {

#[test]
fn doctor_fix_auto_creates_layout_and_inits() {
let _numan_root_guard = crate::util::test_paths::NumanRootRestoreGuard::new();
let dir = TempDir::new().unwrap();
let root = dir.path();
std::fs::create_dir_all(root).unwrap();
Expand Down Expand Up @@ -1889,6 +1890,7 @@ mod tests {

#[test]
fn doctor_fix_adds_official_registry_when_initialized_without_registries() {
let _numan_root_guard = crate::util::test_paths::NumanRootRestoreGuard::new();
let dir = TempDir::new().unwrap();
let root = dir.path();
std::fs::create_dir_all(root.join("nu_state")).unwrap();
Expand Down
93 changes: 93 additions & 0 deletions src/cmd/list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,96 @@ pub fn execute(root: &Path) -> Result<()> {

Ok(())
}

#[cfg(test)]
mod tests {
use super::*;
use crate::state::lockfile::{LockfileEntry, PluginActivation};

fn base_entry(version: &str, package_type: &str) -> LockfileEntry {
LockfileEntry {
version: version.to_string(),
package_type: package_type.to_string(),
source: "binary".to_string(),
target: None,
artifact_url: None,
artifact_sha256: None,
executable_path: None,
archive_root: None,
include: None,
entry: None,
installed_at: "0".to_string(),
nu_version_at_install: None,
activation: None,
registry_url: None,
registry_revision: None,
index_sha256: None,
signing_key_fingerprint: None,
git_url: None,
git_rev: None,
cargo_name: None,
cargo_lock_sha256: None,
built_sha256: None,
payload_path: String::new(),
revision_id: None,
payload_sha256: None,
executable_sha256: None,
selection_reason: None,
origin: None,
module_activation: None,
module_import_mode: None,
locked_dependencies: Default::default(),
}
}

#[test]
fn execute_empty_lockfile() {
let dir = tempfile::tempdir().unwrap();
Lockfile::empty().save(dir.path()).unwrap();
execute(dir.path()).unwrap();
}

#[test]
fn execute_one_package() {
let dir = tempfile::tempdir().unwrap();
let mut lock = Lockfile::empty();
lock.packages
.insert("owner/pkg".to_string(), base_entry("1.0.0", "plugin"));
lock.save(dir.path()).unwrap();
execute(dir.path()).unwrap();
}

#[test]
fn execute_multiple_packages_with_one_active() {
let dir = tempfile::tempdir().unwrap();
let root = dir.path();

let mut lock = Lockfile::empty();
let mut active = base_entry("1.0.0", "plugin");
active.activation = Some(PluginActivation {
plugin_registry_path: "/path/to/plugins.msgpackz".to_string(),
nu_executable_sha256: "abc123".to_string(),
nu_version: "0.113.1".to_string(),
activated_at: "0".to_string(),
});
lock.packages.insert("owner/active".to_string(), active);
lock.packages
.insert("owner/inactive".to_string(), base_entry("2.0.0", "module"));
lock.save(root).unwrap();

std::fs::create_dir_all(root.join("nu_state")).unwrap();
let nu_paths = NuPaths {
nu_executable: "/usr/bin/nu".to_string(),
nu_version: "0.113.1".to_string(),
plugin_registry_path: "/path/to/plugins.msgpackz".to_string(),
nu_executable_hash: "abc123".to_string(),
platform: "x86_64-unknown-linux-gnu".to_string(),
data_dir: None,
vendor_autoload_dirs: vec![],
vendor_autoload_dir: None,
};
nu_paths.save(root).unwrap();

execute(root).unwrap();
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}
68 changes: 68 additions & 0 deletions src/cmd/nu_pin_offer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,71 @@ pub fn is_nu_mismatch(diagnosis: &PackageIncompatibility) -> bool {
| Incompatibility::NuUnsatisfied { .. }
)
}

#[cfg(test)]
mod tests {
use super::*;

fn diagnosis_with_pin(pin: &str) -> PackageIncompatibility {
PackageIncompatibility {
issue: Incompatibility::NuTooOld {
constraint: ">=0.113.0".to_string(),
},
suggested_pin: Some(pin.to_string()),
available_versions: vec![],
}
}

#[test]
fn accept_proceeds_to_install_and_fails_hermetically_on_bad_pin() {
// A malformed pin fails local version normalization before any
// network call, so this exercises the accept branch deterministically.
let dir = tempfile::tempdir().unwrap();
let diagnosis = diagnosis_with_pin("not-a-version");
let err =
offer_managed_nu_pin_with_interaction(dir.path(), "0.112.0", &diagnosis, true, || {
Ok("y\n".to_string())
})
.unwrap_err();
assert!(
err.to_string().contains("Failed to install managed Nu"),
"expected install failure context, got: {err}"
);
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}

#[test]
fn decline_returns_false_without_installing() {
let dir = tempfile::tempdir().unwrap();
let diagnosis = diagnosis_with_pin("0.113.1");
let result =
offer_managed_nu_pin_with_interaction(dir.path(), "0.112.0", &diagnosis, true, || {
Ok("n\n".to_string())
})
.unwrap();
assert!(!result);
}

#[test]
fn invalid_input_is_treated_as_decline() {
let dir = tempfile::tempdir().unwrap();
let diagnosis = diagnosis_with_pin("0.113.1");
let result =
offer_managed_nu_pin_with_interaction(dir.path(), "0.112.0", &diagnosis, true, || {
Ok("maybe\n".to_string())
})
.unwrap();
assert!(!result);
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

#[test]
fn non_interactive_short_circuits_without_reading_input() {
let dir = tempfile::tempdir().unwrap();
let diagnosis = diagnosis_with_pin("0.113.1");
let result =
offer_managed_nu_pin_with_interaction(dir.path(), "0.112.0", &diagnosis, false, || {
panic!("read_line must not be called when non-interactive")
})
.unwrap();
assert!(!result);
}
}
Loading
Loading