diff --git a/src/steps/partition.rs b/src/steps/partition.rs index 6e2dd43..a061c44 100644 --- a/src/steps/partition.rs +++ b/src/steps/partition.rs @@ -1650,3 +1650,188 @@ fn format_number_thousands(n: u64) -> String { } result } + +#[cfg(test)] +mod tests { + use super::*; + use crate::installer::{LogicalVolume, PartitionTableType}; + + fn disk(name: &str, size_gb: u64) -> DiskInfo { + DiskInfo { + name: name.to_string(), + vendor: "ATA".to_string(), + model: "VBOX HARDDISK".to_string(), + drive_type: "HDD".to_string(), + size_gb, + size_bytes: size_gb * 1_073_741_824, + } + } + + fn part(device: &str, size_mb: u64, fstype: FsType, mountpoint: &str) -> CustomPartition { + CustomPartition { + device: device.to_string(), + size_mb, + fstype, + mountpoint: mountpoint.to_string(), + encrypt: false, + luks_password: String::new(), + luks_name: String::new(), + skip_format: false, + } + } + + fn step(uefi: bool) -> PartitionStep { + PartitionStep { + scanned: true, + is_uefi: uefi, + manual: ManualState::default(), + show_luks_password: false, + selected_disk_size_mb: None, + } + } + + // ── make_plan ──────────────────────────────────────────── + + #[test] + fn plan_rejects_small_disk() { + let d = disk("/dev/sdb", 9); + assert!(make_plan(&d, true).is_none()); + assert!(make_plan(&d, false).is_none()); + } + + #[test] + fn plan_uefi_large_disk() { + let d = disk("/dev/sda", 100); + let plan = make_plan(&d, true).expect("100GB disk için plan oluşmalı"); + assert_eq!(plan.disk, "/dev/sda"); + assert_eq!(plan.table_type, PartitionTableType::Gpt); + assert!(plan.efi_mb > 0, "UEFI planında EFI bölümü olmalı"); + // EFI + swap + root, overhead payı düşülmüş disk boyutunu aşmamalı + assert!(plan.efi_mb + plan.swap_mb + plan.root_mb <= 100 * 1024); + } + + #[test] + fn plan_bios_large_disk() { + let d = disk("/dev/sda", 100); + let plan = make_plan(&d, false).expect("100GB disk için plan oluşmalı"); + assert_eq!(plan.table_type, PartitionTableType::Mbr); + assert_eq!(plan.efi_mb, 0, "BIOS modunda EFI bölümü olmamalı"); + } + + // ── validate_manual ─────────────────────────────────────── + + #[test] + fn manual_empty_plan_fails() { + assert!(validate_manual(&[], &[], true).is_some()); + assert!(validate_manual(&[], &[], false).is_some()); + } + + #[test] + fn manual_root_only_ok_on_bios() { + let parts = vec![part("/dev/sda1", 20_000, FsType::Ext4, "/")]; + assert!(validate_manual(&parts, &[], false).is_none()); + } + + #[test] + fn manual_uefi_requires_efi_part() { + let parts = vec![part("/dev/sda1", 20_000, FsType::Ext4, "/")]; + assert!( + validate_manual(&parts, &[], true).is_some(), + "UEFI modunda EFI bölümü zorunlu" + ); + + let with_efi = vec![ + part("/dev/sda1", 300, FsType::Fat32, "/boot/efi"), + part("/dev/sda2", 20_000, FsType::Ext4, "/"), + ]; + assert!(validate_manual(&with_efi, &[], true).is_none()); + } + + #[test] + fn manual_root_can_come_from_lv() { + let parts = vec![part("/dev/sda1", 20_000, FsType::Lvm, "")]; + let lvs = vec![LogicalVolume { + name: "root".to_string(), + vg_name: "vg0".to_string(), + size_mb: 10_000, + fstype: FsType::Ext4, + mountpoint: "/".to_string(), + }]; + assert!(validate_manual(&parts, &lvs, false).is_none()); + } + + // ── InstallerStep arayüzü ───────────────────────────────── + + #[test] + fn auto_mode_complete_only_with_plan() { + let st = step(true); + let mut state = crate::installer::GlobalState::default(); + state.erase_disk = true; + + assert!(!st.is_complete(&state), "plan yokken tamamlanmamalı"); + state.partition_plan = make_plan(&disk("/dev/sda", 100), true); + assert!(st.is_complete(&state), "plan varken tamamlanmalı"); + } + + #[test] + fn manual_mode_complete_with_valid_partitions() { + let st = step(true); + let mut state = crate::installer::GlobalState::default(); + state.erase_disk = false; + + assert!(!st.is_complete(&state), "bölüm yokken tamamlanmamalı"); + + // Kök var ama EFI yok → tamamlanmamalı + state.custom_partitions.push(part("/dev/sda1", 20_000, FsType::Ext4, "/")); + assert!(!st.is_complete(&state), "eksik EFI bölümü ile tamamlanmamalı"); + + // Geçerli düzen → tamamlanmalı + state.custom_partitions.push(part("/dev/sda1", 300, FsType::Fat32, "/boot/efi")); + assert!(st.is_complete(&state), "geçerli düzen ile tamamlanmalı"); + } + + // ── format_number_thousands ─────────────────────────────── + + #[test] + fn formats_thousands() { + assert_eq!(format_number_thousands(0), "0"); + assert_eq!(format_number_thousands(999), "999"); + assert_eq!(format_number_thousands(1000), "1.000"); + assert_eq!(format_number_thousands(7000000), "7.000.000"); + } + + // ── detect_drive_type ───────────────────────────────────── + + #[test] + fn drive_type_by_name() { + assert_eq!(detect_drive_type("nvme0n1"), "NVMe SSD"); + assert_eq!(detect_drive_type("mmcblk0"), "MMC/SD"); + assert_eq!(detect_drive_type("nonexistent99"), "HDD"); + } + + // ── lsblk / sysfs okumaları (canlı sistem) ──────────────── + + #[test] + fn read_existing_partitions_never_panics() { + // Var olmayan disk → boş liste, çökmemeli + assert!(read_existing_partitions("/dev/does-not-exist").is_empty()); + + // Var olan disklerde dönen bölümler /dev/ ön ekli olmalı + for d in list_block_devices().iter().take(1) { + for p in read_existing_partitions(&d.name) { + assert!(p.device.starts_with("/dev/")); + } + } + } + + #[test] + fn list_block_devices_scrubs_loop_ram() { + for d in list_block_devices() { + let base = d.name.trim_start_matches("/dev/"); + assert!(!base.starts_with("loop")); + assert!(!base.starts_with("ram")); + assert!(!base.starts_with("sr")); + assert!(!base.starts_with("zram")); + } + } +}