Skip to content

Commit

Permalink
fix: only show clean modal when projects are selected (#16)
Browse files Browse the repository at this point in the history
  • Loading branch information
devin-ai-integration[bot] authored Jan 1, 2025
1 parent de4504c commit 622f922
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 50 deletions.
3 changes: 3 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ pub mod notify_rw_lock;
pub mod tui;
pub mod tui_app;

/// Size of one gibibyte (GiB) in bytes
pub const GIB_SIZE: u64 = 1024 * 1024 * 1024;

use crate::notify_rw_lock::{NotifyRwLock, NotifySender};
use cargo_toml::Manifest;
use crossbeam_channel::{unbounded, Receiver, Sender};
Expand Down
17 changes: 8 additions & 9 deletions src/tui_app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use uuid::Uuid;
use crate::notify_rw_lock::NotifyRwLock;
use crate::Progress;
use crate::ProjectTargetAnalysis;
use crate::GIB_SIZE;

const DELETE_COMMAND_KEY: char = 'd';
const COLUMNS: usize = 3;
Expand All @@ -33,11 +34,8 @@ impl TableRow for ProjectTargetAnalysis {
Cell::from(self.project_path.to_str().unwrap()).style(Style::default()),
Cell::from(self.project_name.as_deref().unwrap_or("NOT FOUND NAME"))
.style(Style::default()),
Cell::from(format!(
"{:.2}GiB",
self.size as f64 / (1024.0 * 1024.0 * 1024.0)
))
.style(Style::default()),
Cell::from(format!("{:.2}GiB", self.size as f64 / (GIB_SIZE as f64)))
.style(Style::default()),
]
}
}
Expand Down Expand Up @@ -130,7 +128,9 @@ impl App {
}
}
None => {
self.delete_state = Some(DeleteState::Confirm);
if !self.selected_items.is_empty() {
self.delete_state = Some(DeleteState::Confirm);
}
}
}
if is_reset {
Expand Down Expand Up @@ -384,14 +384,13 @@ pub fn status_bar(f: &mut Frame, app: &mut App, rect: Rect) {
])
.split(rect);
let items = app.items.read();
let total_gib_size =
items.iter().map(|it| it.size).sum::<u64>() as f64 / (1024.0 * 1024.0 * 1024.0);
let total_gib_size = items.iter().map(|it| it.size).sum::<u64>() as f64 / (GIB_SIZE as f64);
let selected_gib_size = items
.iter()
.filter(|it| app.selected_items.contains(&it.id))
.map(|it| it.size)
.sum::<u64>() as f64
/ (1024.0 * 1024.0 * 1024.0);
/ (GIB_SIZE as f64);

let status_text = format!(
"Total: {:.2} GiB, Selected: {:.2} GiB",
Expand Down
136 changes: 95 additions & 41 deletions tests/tui_tests.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use cargo_cleaner::{
notify_rw_lock::NotifyRwLock,
tui_app::{after_move, ui, App, CursorMode, DeleteState},
Progress, ProjectTargetAnalysis,
Progress, ProjectTargetAnalysis, GIB_SIZE,
};
use crossterm::event::KeyCode;
use itertools::Itertools;
Expand All @@ -11,6 +11,22 @@ use std::sync::Arc;
use std::time::SystemTime;
use uuid::Uuid;

fn make_project_target(
name: &str,
size: u64,
selected_for_cleanup: bool,
path: Option<String>,
) -> ProjectTargetAnalysis {
ProjectTargetAnalysis {
project_path: std::path::PathBuf::from(path.unwrap_or_else(|| "/test/path".to_string())),
project_name: Some(name.to_string()),
size,
selected_for_cleanup,
last_modified: SystemTime::now(),
id: Uuid::new_v4(),
}
}

/// Test the basic TUI rendering functionality and table content
#[test]
fn test_tui_rendering() {
Expand All @@ -29,14 +45,12 @@ fn test_tui_rendering() {
// Add some mock data to the items
{
let mut items = app.items.write();
items.push(ProjectTargetAnalysis {
project_path: std::path::PathBuf::from("/test/path"),
project_name: Some("test-project".to_string()),
size: 1024 * 1024 * 1024, // 1GB
selected_for_cleanup: true,
last_modified: SystemTime::now(),
id: Uuid::new_v4(),
});
items.push(make_project_target(
"test-project",
GIB_SIZE, // 1GB
true,
None,
));
}

// Render the UI
Expand Down Expand Up @@ -84,14 +98,12 @@ fn test_navigation_and_selection() {
{
let mut items = app.items.write();
for i in 0..3 {
items.push(ProjectTargetAnalysis {
project_path: std::path::PathBuf::from(format!("/test/path{}", i)),
project_name: Some(format!("test-project-{}", i)),
size: 1024 * 1024 * 1024, // 1GB
selected_for_cleanup: true,
last_modified: SystemTime::now(),
id: Uuid::new_v4(),
});
items.push(make_project_target(
&format!("test-project-{}", i),
GIB_SIZE, // 1GB
true,
Some(format!("/test/path{}", i)),
));
}
}

Expand Down Expand Up @@ -149,14 +161,12 @@ fn test_cursor_mode_transitions() {
// Add a mock item
let item_id = {
let mut items = app.items.write();
let item = ProjectTargetAnalysis {
project_path: std::path::PathBuf::from("/test/path"),
project_name: Some("test-project".to_string()),
size: 1024 * 1024 * 1024, // 1GB
selected_for_cleanup: true,
last_modified: SystemTime::now(),
id: Uuid::new_v4(),
};
let item = make_project_target(
"test-project",
GIB_SIZE, // 1GB
true,
None,
);
let id = item.id;
items.push(item);
id
Expand Down Expand Up @@ -280,6 +290,54 @@ fn test_delete_popup() {
assert!(content.contains("Are you sure you want to delete"));
}

/// Test that delete popup doesn't appear when no items are selected
#[test]
fn test_no_delete_popup_when_empty_selection() {
let backend = TestBackend::new(100, 30);
let mut terminal = Terminal::new(backend).unwrap();
let (tx, _rx) = sync_channel(1);
let scan_progress = Arc::new(NotifyRwLock::new(
tx.clone(),
Progress {
total: 0,
scanned: 0,
},
));
let mut app = App::new(true, tx, scan_progress);

// Add some items but don't select any
{
let mut items = app.items.write();
items.push(make_project_target("test-project", GIB_SIZE, false, None));
}

// Verify no delete popup initially
assert!(
app.delete_state.is_none(),
"Delete state should be None initially before pressing 'd' key"
);

// Try to trigger delete popup with 'd' key when no items selected
app.handle_key(KeyCode::Char('d'));

// Verify delete popup did not appear
assert!(
app.delete_state.is_none(),
"Delete state should remain None after pressing 'd' key with no items selected"
);
terminal
.draw(|frame| {
ui(frame, &mut app);
})
.unwrap();
let buffer = terminal.backend().buffer().clone();
let content = buffer_content_to_string(&buffer);
assert!(
!content.contains("Are you sure"),
"Delete confirmation popup should not appear in the UI when no items are selected"
);
}

/// Test status bar rendering
#[test]
fn test_status_bar() {
Expand Down Expand Up @@ -347,22 +405,18 @@ fn test_clean_operation() {
// Add mock items to clean
{
let mut items = app.items.write();
items.push(ProjectTargetAnalysis {
project_path: std::path::PathBuf::from("/test/path1"),
project_name: Some("test-project-1".to_string()),
size: 1024 * 1024 * 1024, // 1GB
selected_for_cleanup: true,
last_modified: SystemTime::now(),
id: Uuid::new_v4(),
});
items.push(ProjectTargetAnalysis {
project_path: std::path::PathBuf::from("/test/path2"),
project_name: Some("test-project-2".to_string()),
size: 2 * 1024 * 1024 * 1024, // 2GB
selected_for_cleanup: true,
last_modified: SystemTime::now(),
id: Uuid::new_v4(),
});
items.push(make_project_target(
"test-project-1",
GIB_SIZE, // 1GB
true,
Some("/test/path1".to_string()),
));
items.push(make_project_target(
"test-project-2",
2 * GIB_SIZE, // 2GB
true,
Some("/test/path2".to_string()),
));
}

// Initial render to verify items are present
Expand Down

0 comments on commit 622f922

Please sign in to comment.