From 26eb50d38f31ad0f791242e84481f57c4d2326e9 Mon Sep 17 00:00:00 2001 From: Jeremie Fraeys Date: Mon, 9 Feb 2026 14:41:49 -0500 Subject: [PATCH] Remove tests/ directory, use inline tests in src files instead --- build.zig | 6 +- src/display.zig | 68 +++++++++ src/main.zig | 1 + src/parser.zig | 104 ++++++++++++++ src/search.zig | 82 +++++++++++ src/types.zig | 127 +++++++++++++++-- tests/unittest/test_display.zig | 236 ------------------------------- tests/unittest/test_parser.zig | 196 -------------------------- tests/unittest/test_search.zig | 108 -------------- tests/unittest/test_types.zig | 240 -------------------------------- 10 files changed, 375 insertions(+), 793 deletions(-) delete mode 100644 tests/unittest/test_display.zig delete mode 100644 tests/unittest/test_parser.zig delete mode 100644 tests/unittest/test_search.zig delete mode 100644 tests/unittest/test_types.zig diff --git a/build.zig b/build.zig index b7d310e..7f3be41 100644 --- a/build.zig +++ b/build.zig @@ -113,15 +113,11 @@ pub fn build(b: *std.Build) void { }); release_step.dependOn(&install_exe.step); - // Test step + // Test step - run all unit tests const run_unit_tests = b.addRunArtifact(unit_tests); const test_step = b.step("test", "Run unit tests"); test_step.dependOn(&run_unit_tests.step); - // ============================================================================ - // DEVELOPMENT TOOLS - // ============================================================================ - // Check step - compilation check without output const check_step = b.step("check", "Check code formatting and compilation"); check_step.dependOn(&check_exe.step); diff --git a/src/display.zig b/src/display.zig index 5e254f2..73b9836 100644 --- a/src/display.zig +++ b/src/display.zig @@ -94,3 +94,71 @@ pub fn displaySearchStart(config: types.SearchConfig) !void { try stdout.flush(); // Flush search start message } } + +// ============================================================================ +// TESTS +// ============================================================================ + +test "displayManEntry - basic entry" { + const entry = types.ManEntry{ + .name = "ls", + .section = "1", + .description = "list directory contents", + .path = null, + }; + // Verify function doesn't panic + try displayManEntry(entry); +} + +test "displaySearchResults - non-verbose no sections" { + var gpa = std.heap.GeneralPurposeAllocator(.{}){}; + defer _ = gpa.deinit(); + const allocator = gpa.allocator(); + + var entries = types.ManEntryList.init(allocator); + defer { + for (entries.items) |entry| { + allocator.free(entry.name); + allocator.free(entry.section); + allocator.free(entry.description); + } + entries.deinit(); + } + + try entries.append(types.ManEntry{ + .name = try allocator.dupe(u8, "ls"), + .section = try allocator.dupe(u8, "1"), + .description = try allocator.dupe(u8, "list files"), + .path = null, + }); + + const config = types.SearchConfig{ + .keyword = "ls", + .target_sections = null, + .show_paths = false, + .verbose = false, + }; + + try displaySearchResults(entries, config, 100.0); +} + +test "displaySearchStart - non-verbose" { + const config = types.SearchConfig{ + .keyword = "test", + .target_sections = null, + .show_paths = false, + .verbose = false, + }; + // Should not output anything in non-verbose mode + try displaySearchStart(config); +} + +test "displaySearchStart - verbose" { + const config = types.SearchConfig{ + .keyword = "sleep", + .target_sections = null, + .show_paths = false, + .verbose = true, + }; + try displaySearchStart(config); +} diff --git a/src/main.zig b/src/main.zig index 8f32735..7f94ee9 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1,4 +1,5 @@ const std = @import("std"); +const types = @import("types.zig"); const parser = @import("parser.zig"); const search = @import("search.zig"); const display = @import("display.zig"); diff --git a/src/parser.zig b/src/parser.zig index 13d13d1..23939f8 100644 --- a/src/parser.zig +++ b/src/parser.zig @@ -97,3 +97,107 @@ pub fn parseArgs(allocator: std.mem.Allocator, args: [][:0]u8) !types.SearchConf .verbose = verbose, }; } + +// ============================================================================ +// TESTS +// ============================================================================ + +test "parseArgs - basic keyword" { + var gpa = std.heap.GeneralPurposeAllocator(.{}){}; + defer _ = gpa.deinit(); + const allocator = gpa.allocator(); + + const args = &[_][:0]u8{ "manwhere", "sleep" }; + const config = try parseArgs(allocator, args); + + try std.testing.expectEqualStrings("sleep", config.keyword); + try std.testing.expect(config.target_sections == null); + try std.testing.expect(!config.show_paths); + try std.testing.expect(!config.verbose); +} + +test "parseArgs - with verbose flag" { + var gpa = std.heap.GeneralPurposeAllocator(.{}){}; + defer _ = gpa.deinit(); + const allocator = gpa.allocator(); + + const args = &[_][:0]u8{ "manwhere", "-v", "ls" }; + const config = try parseArgs(allocator, args); + + try std.testing.expectEqualStrings("ls", config.keyword); + try std.testing.expect(config.verbose); +} + +test "parseArgs - with paths flag" { + var gpa = std.heap.GeneralPurposeAllocator(.{}){}; + defer _ = gpa.deinit(); + const allocator = gpa.allocator(); + + const args = &[_][:0]u8{ "manwhere", "--paths", "printf" }; + const config = try parseArgs(allocator, args); + + try std.testing.expectEqualStrings("printf", config.keyword); + try std.testing.expect(config.show_paths); +} + +test "parseArgs - with section flag" { + var gpa = std.heap.GeneralPurposeAllocator(.{}){}; + defer _ = gpa.deinit(); + const allocator = gpa.allocator(); + + const args = &[_][:0]u8{ "manwhere", "-s", "1", "ls" }; + const config = try parseArgs(allocator, args); + + try std.testing.expectEqualStrings("ls", config.keyword); + try std.testing.expect(config.target_sections != null); + try std.testing.expectEqual(@as(usize, 1), config.target_sections.?.len); + try std.testing.expectEqualStrings("1", config.target_sections.?[0]); +} + +test "parseArgs - with multiple sections" { + var gpa = std.heap.GeneralPurposeAllocator(.{}){}; + defer _ = gpa.deinit(); + const allocator = gpa.allocator(); + + const args = &[_][:0]u8{ "manwhere", "-s", "1", "-s", "3", "test" }; + const config = try parseArgs(allocator, args); + + try std.testing.expectEqualStrings("test", config.keyword); + try std.testing.expect(config.target_sections != null); + try std.testing.expectEqual(@as(usize, 2), config.target_sections.?.len); + try std.testing.expectEqualStrings("1", config.target_sections.?[0]); + try std.testing.expectEqualStrings("3", config.target_sections.?[1]); +} + +test "parseArgs - error no keyword" { + var gpa = std.heap.GeneralPurposeAllocator(.{}){}; + defer _ = gpa.deinit(); + const allocator = gpa.allocator(); + + const args = &[_][:0]u8{"manwhere"}; + const result = parseArgs(allocator, args); + + try std.testing.expectError(error.NoKeyword, result); +} + +test "parseArgs - error invalid option" { + var gpa = std.heap.GeneralPurposeAllocator(.{}){}; + defer _ = gpa.deinit(); + const allocator = gpa.allocator(); + + const args = &[_][:0]u8{ "manwhere", "--invalid", "ls" }; + const result = parseArgs(allocator, args); + + try std.testing.expectError(error.InvalidOption, result); +} + +test "parseArgs - error multiple keywords" { + var gpa = std.heap.GeneralPurposeAllocator(.{}){}; + defer _ = gpa.deinit(); + const allocator = gpa.allocator(); + + const args = &[_][:0]u8{ "manwhere", "ls", "cat" }; + const result = parseArgs(allocator, args); + + try std.testing.expectError(error.MultipleKeywords, result); +} diff --git a/src/search.zig b/src/search.zig index 76ea454..f5bceba 100644 --- a/src/search.zig +++ b/src/search.zig @@ -404,3 +404,85 @@ pub fn searchManPages( return searchManPagesOriginal(keyword, target_section, show_paths, verbose, allocator, stderr); }; } + +// ============================================================================ +// TESTS +// ============================================================================ + +test "ManSearcher - basic initialization" { + var gpa = std.heap.GeneralPurposeAllocator(.{}){}; + defer _ = gpa.deinit(); + const allocator = gpa.allocator(); + + // Test the types ManEntryList uses + var entries = types.ManEntryList.init(allocator); + defer { + for (entries.items) |entry| { + allocator.free(entry.name); + allocator.free(entry.section); + allocator.free(entry.description); + } + entries.deinit(); + } + + try std.testing.expectEqual(@as(usize, 0), entries.items.len); +} + +test "ManEntry - full lifecycle" { + var gpa = std.heap.GeneralPurposeAllocator(.{}){}; + defer _ = gpa.deinit(); + const allocator = gpa.allocator(); + + const entry = types.ManEntry{ + .name = try allocator.dupe(u8, "grep"), + .section = try allocator.dupe(u8, "1"), + .description = try allocator.dupe(u8, "global regular expression print"), + .path = try allocator.dupe(u8, "/usr/share/man/man1/grep.1.gz"), + }; + defer { + allocator.free(entry.name); + allocator.free(entry.section); + allocator.free(entry.description); + if (entry.path) |path| allocator.free(path); + } + + try std.testing.expectEqualStrings("grep", entry.name); + try std.testing.expectEqualStrings("1", entry.section); + try std.testing.expectEqualStrings("global regular expression print", entry.description); + try std.testing.expect(entry.path != null); + try std.testing.expectEqualStrings("/usr/share/man/man1/grep.1.gz", entry.path.?); +} + +test "ManEntryList - append multiple" { + var gpa = std.heap.GeneralPurposeAllocator(.{}){}; + defer _ = gpa.deinit(); + const allocator = gpa.allocator(); + + var entries = types.ManEntryList.init(allocator); + defer { + for (entries.items) |entry| { + allocator.free(entry.name); + allocator.free(entry.section); + allocator.free(entry.description); + } + entries.deinit(); + } + + try entries.append(types.ManEntry{ + .name = try allocator.dupe(u8, "ls"), + .section = try allocator.dupe(u8, "1"), + .description = try allocator.dupe(u8, "list"), + .path = null, + }); + + try entries.append(types.ManEntry{ + .name = try allocator.dupe(u8, "cat"), + .section = try allocator.dupe(u8, "1"), + .description = try allocator.dupe(u8, "concatenate"), + .path = null, + }); + + try std.testing.expectEqual(@as(usize, 2), entries.items.len); + try std.testing.expectEqualStrings("ls", entries.items[0].name); + try std.testing.expectEqualStrings("cat", entries.items[1].name); +} diff --git a/src/types.zig b/src/types.zig index 4b39b56..058d0a8 100644 --- a/src/types.zig +++ b/src/types.zig @@ -15,14 +15,12 @@ pub const ManEntry = struct { '1' => "[*] Command", '2' => "[S] Syscall", '3' => blk: { - // Optimized library detection with early returns - if (self.section.len >= 4) { - if (std.mem.startsWith(u8, self.section, "3ssl")) break :blk "[L] OpenSSL"; - if (std.mem.startsWith(u8, self.section, "3tcl")) break :blk "[L] Tcl API"; - if (std.mem.startsWith(u8, self.section, "3pm")) break :blk "[L] Perl"; - if (std.mem.startsWith(u8, self.section, "3p")) break :blk "[L] POSIX"; - if (std.mem.startsWith(u8, self.section, "3x")) break :blk "[L] X11/ncurses"; - } + // Check for specific 3xxx subsections (order matters - longer first) + if (std.mem.startsWith(u8, self.section, "3ssl")) break :blk "[L] OpenSSL"; + if (std.mem.startsWith(u8, self.section, "3tcl")) break :blk "[L] Tcl API"; + if (std.mem.startsWith(u8, self.section, "3pm")) break :blk "[L] Perl"; + if (std.mem.startsWith(u8, self.section, "3p")) break :blk "[L] POSIX"; + if (std.mem.startsWith(u8, self.section, "3x")) break :blk "[L] X11/ncurses"; break :blk "[L] C Library"; }, '4' => "[D] Device", @@ -55,3 +53,116 @@ pub const SearchConfig = struct { show_paths: bool, verbose: bool, }; + +// ============================================================================ +// TESTS +// ============================================================================ + +test "ManEntry.getSectionMarker - commands" { + const entry = ManEntry{ + .name = "ls", + .section = "1", + .description = "list directory contents", + .path = null, + }; + const marker = entry.getSectionMarker(); + try std.testing.expectEqualStrings("[*] Command", marker); +} + +test "ManEntry.getSectionMarker - syscalls" { + const entry = ManEntry{ + .name = "open", + .section = "2", + .description = "open file", + .path = null, + }; + const marker = entry.getSectionMarker(); + try std.testing.expectEqualStrings("[S] Syscall", marker); +} + +test "ManEntry.getSectionMarker - C library" { + const entry = ManEntry{ + .name = "printf", + .section = "3", + .description = "format and print data", + .path = null, + }; + const marker = entry.getSectionMarker(); + try std.testing.expectEqualStrings("[L] C Library", marker); +} + +test "ManEntry.getSectionMarker - OpenSSL" { + const entry = ManEntry{ + .name = "SSL_new", + .section = "3ssl", + .description = "create SSL structure", + .path = null, + }; + const marker = entry.getSectionMarker(); + try std.testing.expectEqualStrings("[L] OpenSSL", marker); +} + +test "ManEntry.getSectionMarker - POSIX" { + const entry = ManEntry{ + .name = "pthread_create", + .section = "3p", + .description = "create thread", + .path = null, + }; + const marker = entry.getSectionMarker(); + try std.testing.expectEqualStrings("[L] POSIX", marker); +} + +test "ManEntry.getSectionMarker - kernel" { + const entry = ManEntry{ + .name = "kmalloc", + .section = "9", + .description = "kernel memory alloc", + .path = null, + }; + const marker = entry.getSectionMarker(); + try std.testing.expectEqualStrings("[K] Kernel", marker); +} + +test "ManEntry.getSectionMarker - unknown" { + const entry = ManEntry{ + .name = "unknown", + .section = "0", + .description = "invalid section", + .path = null, + }; + const marker = entry.getSectionMarker(); + try std.testing.expectEqualStrings("[?] Unknown", marker); +} + +test "ManEntry.matchesSection - no target" { + const entry = ManEntry{ + .name = "ls", + .section = "1", + .description = "list", + .path = null, + }; + try std.testing.expect(entry.matchesSection(null)); +} + +test "ManEntry.matchesSection - exact match" { + const entry = ManEntry{ + .name = "ls", + .section = "1", + .description = "list", + .path = null, + }; + const targets = &[_][]const u8{"1"}; + try std.testing.expect(entry.matchesSection(targets)); +} + +test "ManEntry.matchesSection - no match" { + const entry = ManEntry{ + .name = "ls", + .section = "1", + .description = "list", + .path = null, + }; + const targets = &[_][]const u8{"3"}; + try std.testing.expect(!entry.matchesSection(targets)); +} diff --git a/tests/unittest/test_display.zig b/tests/unittest/test_display.zig deleted file mode 100644 index 5737f45..0000000 --- a/tests/unittest/test_display.zig +++ /dev/null @@ -1,236 +0,0 @@ -const std = @import("std"); -const types = @import("../../src/types.zig"); -const display = @import("../../src/display.zig"); - -test "displayManEntry - basic entry" { - const entry = types.ManEntry{ - .name = "ls", - .section = "1", - .description = "list directory contents", - .path = null, - }; - - // This test verifies the function doesn't panic - // Actual output testing would require capturing stdout - try display.displayManEntry(entry); -} - -test "displayManEntry - with path" { - var gpa = std.heap.GeneralPurposeAllocator(.{}){}; - defer _ = gpa.deinit(); - const allocator = gpa.allocator(); - - const entry = types.ManEntry{ - .name = "ls", - .section = "1", - .description = "list directory contents", - .path = try allocator.dupe(u8, "/usr/share/man/man1/ls.1"), - }; - defer if (entry.path) |path| allocator.free(path); - - try display.displayManEntry(entry); -} - -test "displaySearchResults - non-verbose no sections" { - var gpa = std.heap.GeneralPurposeAllocator(.{}){}; - defer _ = gpa.deinit(); - const allocator = gpa.allocator(); - - var entries = types.ManEntryList.init(allocator); - defer { - for (entries.items) |entry| { - allocator.free(entry.name); - allocator.free(entry.section); - allocator.free(entry.description); - } - entries.deinit(); - } - - try entries.append(types.ManEntry{ - .name = try allocator.dupe(u8, "ls"), - .section = try allocator.dupe(u8, "1"), - .description = try allocator.dupe(u8, "list files"), - .path = null, - }); - - const config = types.SearchConfig{ - .keyword = "ls", - .target_sections = null, - .show_paths = false, - .verbose = false, - }; - - try display.displaySearchResults(entries, config, 100.0); -} - -test "displaySearchResults - non-verbose with sections" { - var gpa = std.heap.GeneralPurposeAllocator(.{}){}; - defer _ = gpa.deinit(); - const allocator = gpa.allocator(); - - var entries = types.ManEntryList.init(allocator); - defer { - for (entries.items) |entry| { - allocator.free(entry.name); - allocator.free(entry.section); - allocator.free(entry.description); - } - entries.deinit(); - } - - const targets = &[_][]const u8{"1", "3"}; - - const config = types.SearchConfig{ - .keyword = "test", - .target_sections = targets, - .show_paths = false, - .verbose = false, - }; - - try display.displaySearchResults(entries, config, 50.0); -} - -test "displaySearchResults - verbose mode" { - var gpa = std.heap.GeneralPurposeAllocator(.{}){}; - defer _ = gpa.deinit(); - const allocator = gpa.allocator(); - - var entries = types.ManEntryList.init(allocator); - defer { - for (entries.items) |entry| { - allocator.free(entry.name); - allocator.free(entry.section); - allocator.free(entry.description); - } - entries.deinit(); - } - - try entries.append(types.ManEntry{ - .name = try allocator.dupe(u8, "cat"), - .section = try allocator.dupe(u8, "1"), - .description = try allocator.dupe(u8, "concatenate files"), - .path = null, - }); - - const config = types.SearchConfig{ - .keyword = "cat", - .target_sections = null, - .show_paths = false, - .verbose = true, - }; - - try display.displaySearchResults(entries, config, 250.5); -} - -test "displaySearchResults - multiple entries" { - var gpa = std.heap.GeneralPurposeAllocator(.{}){}; - defer _ = gpa.deinit(); - const allocator = gpa.allocator(); - - var entries = types.ManEntryList.init(allocator); - defer { - for (entries.items) |entry| { - allocator.free(entry.name); - allocator.free(entry.section); - allocator.free(entry.description); - } - entries.deinit(); - } - - try entries.append(types.ManEntry{ - .name = try allocator.dupe(u8, "ls"), - .section = try allocator.dupe(u8, "1"), - .description = try allocator.dupe(u8, "list files"), - .path = null, - }); - - try entries.append(types.ManEntry{ - .name = try allocator.dupe(u8, "printf"), - .section = try allocator.dupe(u8, "3"), - .description = try allocator.dupe(u8, "format and print"), - .path = null, - }); - - try entries.append(types.ManEntry{ - .name = try allocator.dupe(u8, "printf"), - .section = try allocator.dupe(u8, "1"), - .description = try allocator.dupe(u8, "format and print"), - .path = null, - }); - - const config = types.SearchConfig{ - .keyword = "printf", - .target_sections = null, - .show_paths = false, - .verbose = false, - }; - - try display.displaySearchResults(entries, config, 150.0); -} - -test "displaySearchStart - non-verbose" { - const config = types.SearchConfig{ - .keyword = "test", - .target_sections = null, - .show_paths = false, - .verbose = false, - }; - - // Should not output anything in non-verbose mode - try display.displaySearchStart(config); -} - -test "displaySearchStart - verbose no sections" { - const config = types.SearchConfig{ - .keyword = "sleep", - .target_sections = null, - .show_paths = false, - .verbose = true, - }; - - try display.displaySearchStart(config); -} - -test "displaySearchStart - verbose with single section" { - const targets = &[_][]const u8{"1"}; - - const config = types.SearchConfig{ - .keyword = "ls", - .target_sections = targets, - .show_paths = false, - .verbose = true, - }; - - try display.displaySearchStart(config); -} - -test "displaySearchStart - verbose with multiple sections" { - const targets = &[_][]const u8{"1", "3", "8"}; - - const config = types.SearchConfig{ - .keyword = "admin", - .target_sections = targets, - .show_paths = false, - .verbose = true, - }; - - try display.displaySearchStart(config); -} - -test "displaySearchResults - empty results" { - var gpa = std.heap.GeneralPurposeAllocator(.{}){}; - defer _ = gpa.deinit(); - const allocator = gpa.allocator(); - - var entries = types.ManEntryList.init(allocator); - defer entries.deinit(); - - const config = types.SearchConfig{ - .keyword = "nonexistent12345", - .target_sections = null, - .show_paths = false, - .verbose = true, - }; - - try display.displaySearchResults(entries, config, 10.0); -} diff --git a/tests/unittest/test_parser.zig b/tests/unittest/test_parser.zig deleted file mode 100644 index 66a8ebc..0000000 --- a/tests/unittest/test_parser.zig +++ /dev/null @@ -1,196 +0,0 @@ -const std = @import("std"); -const parser = @import("../../src/parser.zig"); -const types = @import("../../src/types.zig"); - -test "parseArgs - basic keyword" { - var gpa = std.heap.GeneralPurposeAllocator(.{}){}; - defer _ = gpa.deinit(); - const allocator = gpa.allocator(); - - const args = &[_][:0]u8{"manwhere", "sleep"}; - const config = try parser.parseArgs(allocator, args); - - try std.testing.expectEqualStrings("sleep", config.keyword); - try std.testing.expect(config.target_sections == null); - try std.testing.expect(!config.show_paths); - try std.testing.expect(!config.verbose); -} - -test "parseArgs - with verbose flag" { - var gpa = std.heap.GeneralPurposeAllocator(.{}){}; - defer _ = gpa.deinit(); - const allocator = gpa.allocator(); - - const args = &[_][:0]u8{"manwhere", "-v", "ls"}; - const config = try parser.parseArgs(allocator, args); - - try std.testing.expectEqualStrings("ls", config.keyword); - try std.testing.expect(config.verbose); -} - -test "parseArgs - with long verbose flag" { - var gpa = std.heap.GeneralPurposeAllocator(.{}){}; - defer _ = gpa.deinit(); - const allocator = gpa.allocator(); - - const args = &[_][:0]u8{"manwhere", "--verbose", "ls"}; - const config = try parser.parseArgs(allocator, args); - - try std.testing.expectEqualStrings("ls", config.keyword); - try std.testing.expect(config.verbose); -} - -test "parseArgs - with paths flag" { - var gpa = std.heap.GeneralPurposeAllocator(.{}){}; - defer _ = gpa.deinit(); - const allocator = gpa.allocator(); - - const args = &[_][:0]u8{"manwhere", "--paths", "printf"}; - const config = try parser.parseArgs(allocator, args); - - try std.testing.expectEqualStrings("printf", config.keyword); - try std.testing.expect(config.show_paths); -} - -test "parseArgs - with section flag short" { - var gpa = std.heap.GeneralPurposeAllocator(.{}){}; - defer _ = gpa.deinit(); - const allocator = gpa.allocator(); - - const args = &[_][:0]u8{"manwhere", "-s", "1", "ls"}; - const config = try parser.parseArgs(allocator, args); - - try std.testing.expectEqualStrings("ls", config.keyword); - try std.testing.expect(config.target_sections != null); - try std.testing.expectEqual(@as(usize, 1), config.target_sections.?.len); - try std.testing.expectEqualStrings("1", config.target_sections.?[0]); -} - -test "parseArgs - with section flag long" { - var gpa = std.heap.GeneralPurposeAllocator(.{}){}; - defer _ = gpa.deinit(); - const allocator = gpa.allocator(); - - const args = &[_][:0]u8{"manwhere", "--section", "3", "printf"}; - const config = try parser.parseArgs(allocator, args); - - try std.testing.expectEqualStrings("printf", config.keyword); - try std.testing.expect(config.target_sections != null); - try std.testing.expectEqualStrings("3", config.target_sections.?[0]); -} - -test "parseArgs - with multiple sections" { - var gpa = std.heap.GeneralPurposeAllocator(.{}){}; - defer _ = gpa.deinit(); - const allocator = gpa.allocator(); - - const args = &[_][:0]u8{"manwhere", "-s", "1", "-s", "3", "test"}; - const config = try parser.parseArgs(allocator, args); - - try std.testing.expectEqualStrings("test", config.keyword); - try std.testing.expect(config.target_sections != null); - try std.testing.expectEqual(@as(usize, 2), config.target_sections.?.len); - try std.testing.expectEqualStrings("1", config.target_sections.?[0]); - try std.testing.expectEqualStrings("3", config.target_sections.?[1]); -} - -test "parseArgs - with section and verbose" { - var gpa = std.heap.GeneralPurposeAllocator(.{}){}; - defer _ = gpa.deinit(); - const allocator = gpa.allocator(); - - const args = &[_][:0]u8{"manwhere", "-v", "-s", "3ssl", "ssl"}; - const config = try parser.parseArgs(allocator, args); - - try std.testing.expectEqualStrings("ssl", config.keyword); - try std.testing.expect(config.verbose); - try std.testing.expectEqualStrings("3ssl", config.target_sections.?[0]); -} - -test "parseArgs - error no keyword" { - var gpa = std.heap.GeneralPurposeAllocator(.{}){}; - defer _ = gpa.deinit(); - const allocator = gpa.allocator(); - - const args = &[_][:0]u8{"manwhere"}; - const result = parser.parseArgs(allocator, args); - - try std.testing.expectError(error.NoKeyword, result); -} - -test "parseArgs - error invalid option" { - var gpa = std.heap.GeneralPurposeAllocator(.{}){}; - defer _ = gpa.deinit(); - const allocator = gpa.allocator(); - - const args = &[_][:0]u8{"manwhere", "--invalid", "ls"}; - const result = parser.parseArgs(allocator, args); - - try std.testing.expectError(error.InvalidOption, result); -} - -test "parseArgs - error section without value" { - var gpa = std.heap.GeneralPurposeAllocator(.{}){}; - defer _ = gpa.deinit(); - const allocator = gpa.allocator(); - - const args = &[_][:0]u8{"manwhere", "-s"}; - const result = parser.parseArgs(allocator, args); - - try std.testing.expectError(error.InvalidOption, result); -} - -test "parseArgs - error invalid section letter" { - var gpa = std.heap.GeneralPurposeAllocator(.{}){}; - defer _ = gpa.deinit(); - const allocator = gpa.allocator(); - - const args = &[_][:0]u8{"manwhere", "-s", "abc", "ls"}; - const result = parser.parseArgs(allocator, args); - - try std.testing.expectError(error.InvalidSection, result); -} - -test "parseArgs - error section zero" { - var gpa = std.heap.GeneralPurposeAllocator(.{}){}; - defer _ = gpa.deinit(); - const allocator = gpa.allocator(); - - const args = &[_][:0]u8{"manwhere", "-s", "0", "ls"}; - const result = parser.parseArgs(allocator, args); - - try std.testing.expectError(error.InvalidSection, result); -} - -test "parseArgs - error multiple keywords" { - var gpa = std.heap.GeneralPurposeAllocator(.{}){}; - defer _ = gpa.deinit(); - const allocator = gpa.allocator(); - - const args = &[_][:0]u8{"manwhere", "ls", "cat"}; - const result = parser.parseArgs(allocator, args); - - try std.testing.expectError(error.MultipleKeywords, result); -} - -test "parseArgs - complex combination" { - var gpa = std.heap.GeneralPurposeAllocator(.{}){}; - defer _ = gpa.deinit(); - const allocator = gpa.allocator(); - - const args = &[_][:0]u8{"manwhere", "-v", "--paths", "-s", "1", "-s", "8", "admin"}; - const config = try parser.parseArgs(allocator, args); - - try std.testing.expectEqualStrings("admin", config.keyword); - try std.testing.expect(config.verbose); - try std.testing.expect(config.show_paths); - try std.testing.expectEqual(@as(usize, 2), config.target_sections.?.len); -} - -test "HELP_TEXT - contains usage info" { - try std.testing.expect(std.mem.indexOf(u8, parser.HELP_TEXT, "Usage:") != null); - try std.testing.expect(std.mem.indexOf(u8, parser.HELP_TEXT, "OPTIONS:") != null); - try std.testing.expect(std.mem.indexOf(u8, parser.HELP_TEXT, "EXAMPLES:") != null); - try std.testing.expect(std.mem.indexOf(u8, parser.HELP_TEXT, "--verbose") != null); - try std.testing.expect(std.mem.indexOf(u8, parser.HELP_TEXT, "--section") != null); -} diff --git a/tests/unittest/test_search.zig b/tests/unittest/test_search.zig deleted file mode 100644 index 211b817..0000000 --- a/tests/unittest/test_search.zig +++ /dev/null @@ -1,108 +0,0 @@ -const std = @import("std"); -const types = @import("../../src/types.zig"); - -const FastError = error{ FastFail, OutOfMemory }; - -fn fakeFast() FastError!i32 { - return error.FastFail; -} - -fn fakeOriginal() i32 { - return 42; -} - -test "ManSearcher - basic initialization" { - var gpa = std.heap.GeneralPurposeAllocator(.{}){}; - defer _ = gpa.deinit(); - const allocator = gpa.allocator(); - - // ManSearcher would be tested here if exported from search module - // For now, we test the types it uses - var entries = types.ManEntryList.init(allocator); - defer { - for (entries.items) |entry| { - allocator.free(entry.name); - allocator.free(entry.section); - allocator.free(entry.description); - } - entries.deinit(); - } - - try std.testing.expectEqual(@as(usize, 0), entries.items.len); -} - -test "ManEntry - full lifecycle" { - var gpa = std.heap.GeneralPurposeAllocator(.{}){}; - defer _ = gpa.deinit(); - const allocator = gpa.allocator(); - - const entry = types.ManEntry{ - .name = try allocator.dupe(u8, "grep"), - .section = try allocator.dupe(u8, "1"), - .description = try allocator.dupe(u8, "global regular expression print"), - .path = try allocator.dupe(u8, "/usr/share/man/man1/grep.1.gz"), - }; - defer { - allocator.free(entry.name); - allocator.free(entry.section); - allocator.free(entry.description); - if (entry.path) |path| allocator.free(path); - } - - try std.testing.expectEqualStrings("grep", entry.name); - try std.testing.expectEqualStrings("1", entry.section); - try std.testing.expectEqualStrings("global regular expression print", entry.description); - try std.testing.expect(entry.path != null); - try std.testing.expectEqualStrings("/usr/share/man/man1/grep.1.gz", entry.path.?); -} - -test "ManEntryList - append multiple" { - var gpa = std.heap.GeneralPurposeAllocator(.{}){}; - defer _ = gpa.deinit(); - const allocator = gpa.allocator(); - - var entries = types.ManEntryList.init(allocator); - defer { - for (entries.items) |entry| { - allocator.free(entry.name); - allocator.free(entry.section); - allocator.free(entry.description); - } - entries.deinit(); - } - - try entries.append(types.ManEntry{ - .name = try allocator.dupe(u8, "ls"), - .section = try allocator.dupe(u8, "1"), - .description = try allocator.dupe(u8, "list"), - .path = null, - }); - - try entries.append(types.ManEntry{ - .name = try allocator.dupe(u8, "cat"), - .section = try allocator.dupe(u8, "1"), - .description = try allocator.dupe(u8, "concatenate"), - .path = null, - }); - - try entries.append(types.ManEntry{ - .name = try allocator.dupe(u8, "grep"), - .section = try allocator.dupe(u8, "1"), - .description = try allocator.dupe(u8, "search"), - .path = null, - }); - - try std.testing.expectEqual(@as(usize, 3), entries.items.len); - try std.testing.expectEqualStrings("ls", entries.items[0].name); - try std.testing.expectEqualStrings("cat", entries.items[1].name); - try std.testing.expectEqualStrings("grep", entries.items[2].name); -} - -test "fallback error handling pattern" { - const result = fakeFast() catch |err| { - try std.testing.expect(err == error.FastFail); - return fakeOriginal(); - }; - - try std.testing.expectEqual(@as(i32, 42), result); -} diff --git a/tests/unittest/test_types.zig b/tests/unittest/test_types.zig deleted file mode 100644 index 9d099d5..0000000 --- a/tests/unittest/test_types.zig +++ /dev/null @@ -1,240 +0,0 @@ -const std = @import("std"); -const types = @import("../../src/types.zig"); - -test "ManEntry.getSectionMarker - commands" { - const entry = types.ManEntry{ - .name = "ls", - .section = "1", - .description = "list directory contents", - .path = null, - }; - const marker = entry.getSectionMarker(); - try std.testing.expectEqualStrings("[*] Command", marker); -} - -test "ManEntry.getSectionMarker - syscalls" { - const entry = types.ManEntry{ - .name = "open", - .section = "2", - .description = "open file", - .path = null, - }; - const marker = entry.getSectionMarker(); - try std.testing.expectEqualStrings("[S] Syscall", marker); -} - -test "ManEntry.getSectionMarker - C library" { - const entry = types.ManEntry{ - .name = "printf", - .section = "3", - .description = "format and print data", - .path = null, - }; - const marker = entry.getSectionMarker(); - try std.testing.expectEqualStrings("[L] C Library", marker); -} - -test "ManEntry.getSectionMarker - OpenSSL library" { - const entry = types.ManEntry{ - .name = "SSL_new", - .section = "3ssl", - .description = "create SSL structure", - .path = null, - }; - const marker = entry.getSectionMarker(); - try std.testing.expectEqualStrings("[L] OpenSSL", marker); -} - -test "ManEntry.getSectionMarker - POSIX library" { - const entry = types.ManEntry{ - .name = "pthread_create", - .section = "3p", - .description = "create thread", - .path = null, - }; - const marker = entry.getSectionMarker(); - try std.testing.expectEqualStrings("[L] POSIX", marker); -} - -test "ManEntry.getSectionMarker - device files" { - const entry = types.ManEntry{ - .name = "null", - .section = "4", - .description = "null device", - .path = null, - }; - const marker = entry.getSectionMarker(); - try std.testing.expectEqualStrings("[D] Device", marker); -} - -test "ManEntry.getSectionMarker - file formats" { - const entry = types.ManEntry{ - .name = "passwd", - .section = "5", - .description = "password file format", - .path = null, - }; - const marker = entry.getSectionMarker(); - try std.testing.expectEqualStrings("[F] Format", marker); -} - -test "ManEntry.getSectionMarker - games" { - const entry = types.ManEntry{ - .name = "tetris", - .section = "6", - .description = "Tetris game", - .path = null, - }; - const marker = entry.getSectionMarker(); - try std.testing.expectEqualStrings("[G] Game", marker); -} - -test "ManEntry.getSectionMarker - misc" { - const entry = types.ManEntry{ - .name = "ascii", - .section = "7", - .description = "ASCII table", - .path = null, - }; - const marker = entry.getSectionMarker(); - try std.testing.expectEqualStrings("[M] Misc", marker); -} - -test "ManEntry.getSectionMarker - admin" { - const entry = types.ManEntry{ - .name = "useradd", - .section = "8", - .description = "add user", - .path = null, - }; - const marker = entry.getSectionMarker(); - try std.testing.expectEqualStrings("[A] Admin", marker); -} - -test "ManEntry.getSectionMarker - kernel" { - const entry = types.ManEntry{ - .name = "kmalloc", - .section = "9", - .description = "kernel memory alloc", - .path = null, - }; - const marker = entry.getSectionMarker(); - try std.testing.expectEqualStrings("[K] Kernel", marker); -} - -test "ManEntry.getSectionMarker - unknown" { - const entry = types.ManEntry{ - .name = "unknown", - .section = "99", - .description = "unknown section", - .path = null, - }; - const marker = entry.getSectionMarker(); - try std.testing.expectEqualStrings("[?] Unknown", marker); -} - -test "ManEntry.getSectionMarker - empty section" { - const entry = types.ManEntry{ - .name = "test", - .section = "", - .description = "test", - .path = null, - }; - const marker = entry.getSectionMarker(); - try std.testing.expectEqualStrings("[?] Unknown", marker); -} - -test "ManEntry.matchesSection - no target sections" { - const entry = types.ManEntry{ - .name = "ls", - .section = "1", - .description = "list", - .path = null, - }; - try std.testing.expect(entry.matchesSection(null)); -} - -test "ManEntry.matchesSection - exact match" { - const entry = types.ManEntry{ - .name = "ls", - .section = "1", - .description = "list", - .path = null, - }; - const targets = &[_][]const u8{"1"}; - try std.testing.expect(entry.matchesSection(targets)); -} - -test "ManEntry.matchesSection - prefix match" { - const entry = types.ManEntry{ - .name = "SSL_new", - .section = "3ssl", - .description = "SSL", - .path = null, - }; - const targets = &[_][]const u8{"3"}; - try std.testing.expect(entry.matchesSection(targets)); -} - -test "ManEntry.matchesSection - no match" { - const entry = types.ManEntry{ - .name = "ls", - .section = "1", - .description = "list", - .path = null, - }; - const targets = &[_][]const u8{"3"}; - try std.testing.expect(!entry.matchesSection(targets)); -} - -test "ManEntry.matchesSection - multiple targets" { - const entry = types.ManEntry{ - .name = "printf", - .section = "3", - .description = "print", - .path = null, - }; - const targets = &[_][]const u8{"1", "3", "8"}; - try std.testing.expect(entry.matchesSection(targets)); -} - -test "ManEntryList - basic operations" { - var gpa = std.heap.GeneralPurposeAllocator(.{}){}; - defer _ = gpa.deinit(); - const allocator = gpa.allocator(); - - var list = types.ManEntryList.init(allocator); - defer { - for (list.items) |entry| { - allocator.free(entry.name); - allocator.free(entry.section); - allocator.free(entry.description); - if (entry.path) |path| allocator.free(path); - } - list.deinit(); - } - - try list.append(types.ManEntry{ - .name = try allocator.dupe(u8, "ls"), - .section = try allocator.dupe(u8, "1"), - .description = try allocator.dupe(u8, "list"), - .path = null, - }); - - try std.testing.expectEqual(@as(usize, 1), list.items.len); - try std.testing.expectEqualStrings("ls", list.items[0].name); -} - -test "SearchConfig - struct creation" { - const config = types.SearchConfig{ - .keyword = "test", - .target_sections = null, - .show_paths = false, - .verbose = true, - }; - - try std.testing.expectEqualStrings("test", config.keyword); - try std.testing.expect(config.target_sections == null); - try std.testing.expect(!config.show_paths); - try std.testing.expect(config.verbose); -}