Merge pull request #58 from SamTebbs33/feature/arch-mock-testing
Feature/arch mock testing
This commit is contained in:
		
						commit
						b046cd8f3e
					
				
					 24 changed files with 1812 additions and 829 deletions
				
			
		
							
								
								
									
										25
									
								
								README.md
									
										
									
									
									
								
							
							
						
						
									
										25
									
								
								README.md
									
										
									
									
									
								
							| 
						 | 
					@ -7,37 +7,46 @@ Pluto is a kernel written almost entirely in [Zig](https://github.com/ziglang/zi
 | 
				
			||||||

 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Goals
 | 
					## Goals
 | 
				
			||||||
 | 
					
 | 
				
			||||||
* **Should be written in Zig as much as possible**. Assembly should only be used where required for functionality or performance reasons.
 | 
					* **Should be written in Zig as much as possible**. Assembly should only be used where required for functionality or performance reasons.
 | 
				
			||||||
* **Light and performant**. The kernel should be usable both on embedded and desktop class CPUs, made possible by it being lightweight and modular.
 | 
					* **Light and performant**. The kernel should be usable both on embedded and desktop class CPUs, made possible by it being lightweight and modular.
 | 
				
			||||||
* **Basic utilities will be written in Zig**. This includes a basic text editor and shell, and will be part of the filsystem external to the kernel itself.
 | 
					* **Basic utilities will be written in Zig**. This includes a basic text editor and shell, and will be part of the filesystem external to the kernel itself.
 | 
				
			||||||
* **Easy to port**. The kernel is oblivous to the underlying architecture, meaning that ports only need to implement the defined interface and they should work without a hitch.
 | 
					* **Easy to port**. The kernel is oblivious to the underlying architecture, meaning that ports only need to implement the defined interface and they should work without a hitch.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
All of these goals will benefit from the features of Zig.
 | 
					All of these goals will benefit from the features of Zig.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Build
 | 
					## Build
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Requires a master build of Zig ([downloaded](https://ziglang.org/download) or [built from source](https://github.com/ziglang/zig#building-from-source)) *xorriso* and the grub tools (such as *grub-mkrescue*). A gdb binary compatible with your chosen target is required to run the kernel (e.g. *qemu-system-i386*).
 | 
					Requires a master build of Zig ([downloaded](https://ziglang.org/download) or [built from source](https://github.com/ziglang/zig#building-from-source)) *xorriso* and the grub tools (such as *grub-mkrescue*). A gdb binary compatible with your chosen target is required to run the kernel (e.g. *qemu-system-i386*).
 | 
				
			||||||
```
 | 
					
 | 
				
			||||||
 | 
					```Shell
 | 
				
			||||||
zig build
 | 
					zig build
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Run
 | 
					## Run
 | 
				
			||||||
```
 | 
					
 | 
				
			||||||
 | 
					```Shell
 | 
				
			||||||
zig build run
 | 
					zig build run
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Debug
 | 
					## Debug
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Launch a gdb instance and connect to qemu.
 | 
					Launch a gdb instance and connect to qemu.
 | 
				
			||||||
```
 | 
					
 | 
				
			||||||
 | 
					```Shell
 | 
				
			||||||
zig build debug
 | 
					zig build debug
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Test
 | 
					## Test
 | 
				
			||||||
Run the unitests or runtime tests.
 | 
					
 | 
				
			||||||
```
 | 
					Run the unit tests or runtime tests.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```Shell
 | 
				
			||||||
zig build test
 | 
					zig build test
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Options
 | 
					## Options
 | 
				
			||||||
 | 
					
 | 
				
			||||||
* `-Ddebug=`: Boolean (default `false`).
 | 
					* `-Ddebug=`: Boolean (default `false`).
 | 
				
			||||||
  * **build**: Build with debug info included or stripped (see #70 for planned changes).
 | 
					  * **build**: Build with debug info included or stripped (see #70 for planned changes).
 | 
				
			||||||
  * **run**: Wait for a gdb connection before executing.
 | 
					  * **run**: Wait for a gdb connection before executing.
 | 
				
			||||||
| 
						 | 
					@ -46,9 +55,11 @@ zig build test
 | 
				
			||||||
  * **test**: Run the runtime testing script instead of the unittests. Checks for the expected log statements and fails if any are missing.
 | 
					  * **test**: Run the runtime testing script instead of the unittests. Checks for the expected log statements and fails if any are missing.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Contribution
 | 
					## Contribution
 | 
				
			||||||
 | 
					
 | 
				
			||||||
We welcome all contributions, be it bug reports, feature suggestions or pull requests. We follow the style mandated by zig fmt so make sure you've run `zig fmt` on your code before submitting it.
 | 
					We welcome all contributions, be it bug reports, feature suggestions or pull requests. We follow the style mandated by zig fmt so make sure you've run `zig fmt` on your code before submitting it.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
We also like to order a file's members (public after non-public):
 | 
					We also like to order a file's members (public after non-public):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
1. imports
 | 
					1. imports
 | 
				
			||||||
2. type definitions
 | 
					2. type definitions
 | 
				
			||||||
3. constants
 | 
					3. constants
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,9 +27,8 @@ steps:
 | 
				
			||||||
- script: zig*/zig build
 | 
					- script: zig*/zig build
 | 
				
			||||||
  displayName: 'Build kernel'
 | 
					  displayName: 'Build kernel'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Uncomment once mock testing is finished
 | 
					- script: zig*/zig build test
 | 
				
			||||||
#- script: zig*/zig build test
 | 
					  displayName: 'Unit tests'
 | 
				
			||||||
#  displayName: 'Mocked tests'
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
- script: |
 | 
					- script: |
 | 
				
			||||||
    sudo apt-get update
 | 
					    sudo apt-get update
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										26
									
								
								build.zig
									
										
									
									
									
								
							
							
						
						
									
										26
									
								
								build.zig
									
										
									
									
									
								
							| 
						 | 
					@ -4,6 +4,7 @@ const Builder = std.build.Builder;
 | 
				
			||||||
const Step = std.build.Step;
 | 
					const Step = std.build.Step;
 | 
				
			||||||
const Target = std.build.Target;
 | 
					const Target = std.build.Target;
 | 
				
			||||||
const fs = std.fs;
 | 
					const fs = std.fs;
 | 
				
			||||||
 | 
					const Mode = builtin.Mode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn build(b: *Builder) !void {
 | 
					pub fn build(b: *Builder) !void {
 | 
				
			||||||
    const target = Target{
 | 
					    const target = Target{
 | 
				
			||||||
| 
						 | 
					@ -13,12 +14,19 @@ pub fn build(b: *Builder) !void {
 | 
				
			||||||
            .abi = .gnu,
 | 
					            .abi = .gnu,
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const target_str = switch (target.getArch()) {
 | 
				
			||||||
 | 
					        builtin.Arch.i386 => "x86",
 | 
				
			||||||
 | 
					        else => unreachable,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
    const debug = b.option(bool, "debug", "build with debug symbols / make qemu wait for a debug connection") orelse false;
 | 
					    const debug = b.option(bool, "debug", "build with debug symbols / make qemu wait for a debug connection") orelse false;
 | 
				
			||||||
    const rt_test = b.option(bool, "rt-test", "enable/disable runtime testing") orelse false;
 | 
					    const rt_test = b.option(bool, "rt-test", "enable/disable runtime testing") orelse false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const main_src = "src/kernel/kmain.zig";
 | 
					    const main_src = "src/kernel/kmain.zig";
 | 
				
			||||||
    const exec = b.addExecutable("pluto", main_src);
 | 
					    const exec = b.addExecutable("pluto", main_src);
 | 
				
			||||||
    exec.setMainPkgPath(".");
 | 
					    exec.setMainPkgPath(".");
 | 
				
			||||||
 | 
					    const const_path = try fs.path.join(b.allocator, [_][]const u8{ "src/kernel/arch/", target_str, "/constants.zig" });
 | 
				
			||||||
 | 
					    exec.addPackagePath("constants", const_path);
 | 
				
			||||||
    exec.addBuildOption(bool, "rt_test", rt_test);
 | 
					    exec.addBuildOption(bool, "rt_test", rt_test);
 | 
				
			||||||
    exec.setLinkerScriptPath("link.ld");
 | 
					    exec.setLinkerScriptPath("link.ld");
 | 
				
			||||||
    exec.setTheTarget(target);
 | 
					    exec.setTheTarget(target);
 | 
				
			||||||
| 
						 | 
					@ -72,11 +80,18 @@ pub fn build(b: *Builder) !void {
 | 
				
			||||||
        const script = b.addSystemCommand([_][]const u8{ "python3", "test/rt-test.py", "x86", b.zig_exe });
 | 
					        const script = b.addSystemCommand([_][]const u8{ "python3", "test/rt-test.py", "x86", b.zig_exe });
 | 
				
			||||||
        test_step.dependOn(&script.step);
 | 
					        test_step.dependOn(&script.step);
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        const unit_tests = b.addTest(main_src);
 | 
					        inline for ([_]Mode{ Mode.Debug, Mode.ReleaseFast, Mode.ReleaseSafe, Mode.ReleaseSmall }) |test_mode| {
 | 
				
			||||||
 | 
					            const mode_str = comptime modeToString(test_mode);
 | 
				
			||||||
 | 
					            const unit_tests = b.addTest("test/unittests/test_all.zig");
 | 
				
			||||||
 | 
					            unit_tests.setBuildMode(test_mode);
 | 
				
			||||||
            unit_tests.setMainPkgPath(".");
 | 
					            unit_tests.setMainPkgPath(".");
 | 
				
			||||||
 | 
					            unit_tests.setNamePrefix(mode_str ++ " - ");
 | 
				
			||||||
 | 
					            unit_tests.addPackagePath("mocking", "test/mock/kernel/mocking.zig");
 | 
				
			||||||
 | 
					            unit_tests.addPackagePath("constants", const_path);
 | 
				
			||||||
            unit_tests.addBuildOption(bool, "rt_test", rt_test);
 | 
					            unit_tests.addBuildOption(bool, "rt_test", rt_test);
 | 
				
			||||||
            test_step.dependOn(&unit_tests.step);
 | 
					            test_step.dependOn(&unit_tests.step);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const debug_step = b.step("debug", "Debug with gdb");
 | 
					    const debug_step = b.step("debug", "Debug with gdb");
 | 
				
			||||||
    const debug_cmd = b.addSystemCommand([_][]const u8{
 | 
					    const debug_cmd = b.addSystemCommand([_][]const u8{
 | 
				
			||||||
| 
						 | 
					@ -91,3 +106,12 @@ pub fn build(b: *Builder) !void {
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    debug_step.dependOn(&debug_cmd.step);
 | 
					    debug_step.dependOn(&debug_cmd.step);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn modeToString(comptime mode: Mode) []const u8 {
 | 
				
			||||||
 | 
					    return switch (mode) {
 | 
				
			||||||
 | 
					        Mode.Debug => "debug",
 | 
				
			||||||
 | 
					        Mode.ReleaseFast => "release-fast",
 | 
				
			||||||
 | 
					        Mode.ReleaseSafe => "release-safe",
 | 
				
			||||||
 | 
					        Mode.ReleaseSmall => "release-small",
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,6 @@
 | 
				
			||||||
const builtin = @import("builtin");
 | 
					const builtin = @import("builtin");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub const internals = switch (builtin.arch) {
 | 
					pub const internals = if (builtin.is_test) @import("mocking").arch else switch (builtin.arch) {
 | 
				
			||||||
    builtin.Arch.i386 => @import("arch/x86/arch.zig"),
 | 
					    builtin.Arch.i386 => @import("arch/x86/arch.zig"),
 | 
				
			||||||
    else => unreachable,
 | 
					    else => unreachable,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,6 @@
 | 
				
			||||||
// Zig version: 0.4.0
 | 
					// Zig version: 0.4.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const std = @import("std");
 | 
				
			||||||
const builtin = @import("builtin");
 | 
					const builtin = @import("builtin");
 | 
				
			||||||
const gdt = @import("gdt.zig");
 | 
					const gdt = @import("gdt.zig");
 | 
				
			||||||
const idt = @import("idt.zig");
 | 
					const idt = @import("idt.zig");
 | 
				
			||||||
| 
						 | 
					@ -7,6 +8,8 @@ const irq = @import("irq.zig");
 | 
				
			||||||
const isr = @import("isr.zig");
 | 
					const isr = @import("isr.zig");
 | 
				
			||||||
const log = @import("../../log.zig");
 | 
					const log = @import("../../log.zig");
 | 
				
			||||||
const pit = @import("pit.zig");
 | 
					const pit = @import("pit.zig");
 | 
				
			||||||
 | 
					const paging = @import("paging.zig");
 | 
				
			||||||
 | 
					const MemProfile = @import("../../mem.zig").MemProfile;
 | 
				
			||||||
const syscalls = @import("syscalls.zig");
 | 
					const syscalls = @import("syscalls.zig");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub const InterruptContext = struct {
 | 
					pub const InterruptContext = struct {
 | 
				
			||||||
| 
						 | 
					@ -39,9 +42,6 @@ pub const InterruptContext = struct {
 | 
				
			||||||
    user_esp: u32,
 | 
					    user_esp: u32,
 | 
				
			||||||
    ss: u32,
 | 
					    ss: u32,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
const paging = @import("paging.zig");
 | 
					 | 
				
			||||||
const std = @import("std");
 | 
					 | 
				
			||||||
const MemProfile = @import("../../mem.zig").MemProfile;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// Initialise the architecture
 | 
					/// Initialise the architecture
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,4 @@
 | 
				
			||||||
const constants = @import("constants.zig");
 | 
					const constants = @import("constants");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const ALIGN = 1 << 0;
 | 
					const ALIGN = 1 << 0;
 | 
				
			||||||
const MEMINFO = 1 << 1;
 | 
					const MEMINFO = 1 << 1;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,7 +7,8 @@ const MemProfile = @import("../../mem.zig").MemProfile;
 | 
				
			||||||
const testing = @import("std").testing;
 | 
					const testing = @import("std").testing;
 | 
				
			||||||
const expectEqual = testing.expectEqual;
 | 
					const expectEqual = testing.expectEqual;
 | 
				
			||||||
const expect = testing.expect;
 | 
					const expect = testing.expect;
 | 
				
			||||||
const constants = @import("constants.zig");
 | 
					
 | 
				
			||||||
 | 
					extern var KERNEL_ADDR_OFFSET: *u32;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const ENTRIES_PER_DIRECTORY = 1024;
 | 
					const ENTRIES_PER_DIRECTORY = 1024;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -34,7 +35,7 @@ const ENTRY_AVAILABLE = 0xE00;
 | 
				
			||||||
const ENTRY_PAGE_ADDR = 0xFFC00000;
 | 
					const ENTRY_PAGE_ADDR = 0xFFC00000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const Directory = packed struct {
 | 
					const Directory = packed struct {
 | 
				
			||||||
    entries: [ENTRIES_PER_DIRECTORY]DirectoryEntry
 | 
					    entries: [ENTRIES_PER_DIRECTORY]DirectoryEntry,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const PagingError = error {
 | 
					const PagingError = error {
 | 
				
			||||||
| 
						 | 
					@ -42,7 +43,7 @@ const PagingError = error {
 | 
				
			||||||
    InvalidVirtAddresses,
 | 
					    InvalidVirtAddresses,
 | 
				
			||||||
    PhysicalVirtualMismatch,
 | 
					    PhysicalVirtualMismatch,
 | 
				
			||||||
    UnalignedPhysAddresses,
 | 
					    UnalignedPhysAddresses,
 | 
				
			||||||
    UnalignedVirtAddresses
 | 
					    UnalignedVirtAddresses,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
| 
						 | 
					@ -140,7 +141,7 @@ pub fn init(mem_profile: *const MemProfile, allocator: *std.mem.Allocator) void
 | 
				
			||||||
    @memset(@ptrCast([*]u8, kernel_directory), 0, @sizeOf(Directory));
 | 
					    @memset(@ptrCast([*]u8, kernel_directory), 0, @sizeOf(Directory));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    mapDir(kernel_directory, p_start, p_end, v_start, v_end, allocator) catch unreachable;
 | 
					    mapDir(kernel_directory, p_start, p_end, v_start, v_end, allocator) catch unreachable;
 | 
				
			||||||
    const dir_physaddr = @ptrToInt(kernel_directory) - constants.KERNEL_ADDR_OFFSET;
 | 
					    const dir_physaddr = @ptrToInt(kernel_directory) - @ptrToInt(&KERNEL_ADDR_OFFSET);
 | 
				
			||||||
    asm volatile ("mov %[addr], %%cr3" :: [addr] "{eax}" (dir_physaddr));
 | 
					    asm volatile ("mov %[addr], %%cr3" :: [addr] "{eax}" (dir_physaddr));
 | 
				
			||||||
    isr.registerIsr(14, pageFault) catch unreachable;
 | 
					    isr.registerIsr(14, pageFault) catch unreachable;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,13 +2,13 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const std = @import("std");
 | 
					const std = @import("std");
 | 
				
			||||||
const builtin = @import("builtin");
 | 
					const builtin = @import("builtin");
 | 
				
			||||||
const arch = if (builtin.is_test) @import("../../test/kernel/arch_mock.zig") else @import("arch.zig").internals;
 | 
					const arch = @import("arch.zig").internals;
 | 
				
			||||||
const multiboot = @import("multiboot.zig");
 | 
					const multiboot = @import("multiboot.zig");
 | 
				
			||||||
const tty = @import("tty.zig");
 | 
					const tty = @import("tty.zig");
 | 
				
			||||||
const vga = @import("vga.zig");
 | 
					const vga = @import("vga.zig");
 | 
				
			||||||
const log = @import("log.zig");
 | 
					const log = @import("log.zig");
 | 
				
			||||||
const serial = @import("serial.zig");
 | 
					const serial = @import("serial.zig");
 | 
				
			||||||
const mem = @import("mem.zig");
 | 
					const mem = if (builtin.is_test) @import("mocking").mem else @import("mem.zig");
 | 
				
			||||||
const options = @import("build_options");
 | 
					const options = @import("build_options");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
comptime {
 | 
					comptime {
 | 
				
			||||||
| 
						 | 
					@ -18,9 +18,13 @@ comptime {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// This is for unit testing as we need to export KERNEL_ADDR_OFFSET as it is no longer available
 | 
				
			||||||
 | 
					// from the linker script
 | 
				
			||||||
 | 
					export var KERNEL_ADDR_OFFSET: u32 = if (builtin.is_test) 0xC0000000 else undefined;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Need to import this as we need the panic to be in the root source file, or zig will just use the
 | 
					// Need to import this as we need the panic to be in the root source file, or zig will just use the
 | 
				
			||||||
// builtin panic and just loop, which is what we don't want
 | 
					// builtin panic and just loop, which is what we don't want
 | 
				
			||||||
const panic_root = @import("panic.zig");
 | 
					const panic_root = if (builtin.is_test) @import("mocking").panic else @import("panic.zig");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Just call the panic function, as this need to be in the root source file
 | 
					// Just call the panic function, as this need to be in the root source file
 | 
				
			||||||
pub fn panic(msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn {
 | 
					pub fn panic(msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,7 +5,7 @@ pub const Level = enum {
 | 
				
			||||||
    INFO,
 | 
					    INFO,
 | 
				
			||||||
    DEBUG,
 | 
					    DEBUG,
 | 
				
			||||||
    WARNING,
 | 
					    WARNING,
 | 
				
			||||||
    ERROR
 | 
					    ERROR,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn logCallback(context: void, str: []const u8) anyerror!void {
 | 
					fn logCallback(context: void, str: []const u8) anyerror!void {
 | 
				
			||||||
| 
						 | 
					@ -23,9 +23,11 @@ pub fn logInfo(comptime format: []const u8, args: ...) void {
 | 
				
			||||||
pub fn logDebug(comptime format: []const u8, args: ...) void {
 | 
					pub fn logDebug(comptime format: []const u8, args: ...) void {
 | 
				
			||||||
    log(Level.DEBUG, format, args);
 | 
					    log(Level.DEBUG, format, args);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn logWarning(comptime format: []const u8, args: ...) void {
 | 
					pub fn logWarning(comptime format: []const u8, args: ...) void {
 | 
				
			||||||
    log(Level.WARNING, format, args);
 | 
					    log(Level.WARNING, format, args);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn logError(comptime format: []const u8, args: ...) void {
 | 
					pub fn logError(comptime format: []const u8, args: ...) void {
 | 
				
			||||||
    log(Level.ERROR, format, args);
 | 
					    log(Level.ERROR, format, args);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,7 +6,7 @@ pub const MemProfile = struct {
 | 
				
			||||||
    physaddr_end: [*]u8,
 | 
					    physaddr_end: [*]u8,
 | 
				
			||||||
    physaddr_start: [*]u8,
 | 
					    physaddr_start: [*]u8,
 | 
				
			||||||
    mem_kb: u32,
 | 
					    mem_kb: u32,
 | 
				
			||||||
    fixed_alloc_size: u32
 | 
					    fixed_alloc_size: u32,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// The virtual/physical start/end of the kernel code
 | 
					// The virtual/physical start/end of the kernel code
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,7 +2,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const builtin = @import("builtin");
 | 
					const builtin = @import("builtin");
 | 
				
			||||||
const tty = @import("tty.zig");
 | 
					const tty = @import("tty.zig");
 | 
				
			||||||
const arch = if (builtin.is_test) @import("../../test/kernel/arch_mock.zig") else @import("arch.zig").internals;
 | 
					const arch = @import("arch.zig").internals;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn panicFmt(trace: ?*builtin.StackTrace, comptime format: []const u8, args: ...) noreturn {
 | 
					pub fn panicFmt(trace: ?*builtin.StackTrace, comptime format: []const u8, args: ...) noreturn {
 | 
				
			||||||
    @setCold(true);
 | 
					    @setCold(true);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
					@ -1,70 +1,64 @@
 | 
				
			||||||
// Zig version: 0.4.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const builtin = @import("builtin");
 | 
					 | 
				
			||||||
const arch = @import("arch.zig").internals;
 | 
					const arch = @import("arch.zig").internals;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const expectEqual = @import("std").testing.expectEqual;
 | 
					 | 
				
			||||||
const warn = @import("std").debug.warn;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// The port address for the VGA register selection.
 | 
					/// The port address for the VGA register selection.
 | 
				
			||||||
const PORT_ADDRESS: u16 = 0x03D4;
 | 
					pub const PORT_ADDRESS: u16 = 0x03D4;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// The port address for the VGA data.
 | 
					/// The port address for the VGA data.
 | 
				
			||||||
const PORT_DATA: u16 = 0x03D5;
 | 
					pub const PORT_DATA: u16    = 0x03D5;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// The indexes that is passed to the address port to select the register for the data to be
 | 
					/// The indexes that is passed to the address port to select the register for the data to be
 | 
				
			||||||
// read or written to.
 | 
					/// read or written to.
 | 
				
			||||||
const REG_HORIZONTAL_TOTAL: u8                = 0x00;
 | 
					pub const REG_HORIZONTAL_TOTAL: u8                = 0x00;
 | 
				
			||||||
const REG_HORIZONTAL_DISPLAY_ENABLE_END: u8   = 0x01;
 | 
					pub const REG_HORIZONTAL_DISPLAY_ENABLE_END: u8   = 0x01;
 | 
				
			||||||
const REG_START_HORIZONTAL_BLINKING: u8       = 0x02;
 | 
					pub const REG_START_HORIZONTAL_BLINKING: u8       = 0x02;
 | 
				
			||||||
const REG_END_HORIZONTAL_BLINKING: u8         = 0x03;
 | 
					pub const REG_END_HORIZONTAL_BLINKING: u8         = 0x03;
 | 
				
			||||||
const REG_START_HORIZONTAL_RETRACE_PULSE: u8  = 0x04;
 | 
					pub const REG_START_HORIZONTAL_RETRACE_PULSE: u8  = 0x04;
 | 
				
			||||||
const REG_END_HORIZONTAL_RETRACE_PULSE: u8    = 0x05;
 | 
					pub const REG_END_HORIZONTAL_RETRACE_PULSE: u8    = 0x05;
 | 
				
			||||||
const REG_VERTICAL_TOTAL: u8                  = 0x06;
 | 
					pub const REG_VERTICAL_TOTAL: u8                  = 0x06;
 | 
				
			||||||
const REG_OVERFLOW: u8                        = 0x07;
 | 
					pub const REG_OVERFLOW: u8                        = 0x07;
 | 
				
			||||||
const REG_PRESET_ROW_SCAN: u8                 = 0x08;
 | 
					pub const REG_PRESET_ROW_SCAN: u8                 = 0x08;
 | 
				
			||||||
const REG_MAXIMUM_SCAN_LINE: u8               = 0x09;
 | 
					pub const REG_MAXIMUM_SCAN_LINE: u8               = 0x09;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// The command for setting the start of the cursor scan line.
 | 
					/// The register select for setting the cursor scan lines.
 | 
				
			||||||
const REG_CURSOR_START: u8                    = 0x0A;
 | 
					pub const REG_CURSOR_START: u8                    = 0x0A;
 | 
				
			||||||
 | 
					pub const REG_CURSOR_END: u8                      = 0x0B;
 | 
				
			||||||
 | 
					pub const REG_START_ADDRESS_HIGH: u8              = 0x0C;
 | 
				
			||||||
 | 
					pub const REG_START_ADDRESS_LOW: u8               = 0x0D;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// The command for setting the end of the cursor scan line.
 | 
					/// The command for setting the cursor's linear location.
 | 
				
			||||||
const REG_CURSOR_END: u8                      = 0x0B;
 | 
					pub const REG_CURSOR_LOCATION_HIGH: u8            = 0x0E;
 | 
				
			||||||
const REG_START_ADDRESS_HIGH: u8              = 0x0C;
 | 
					pub const REG_CURSOR_LOCATION_LOW: u8             = 0x0F;
 | 
				
			||||||
const REG_START_ADDRESS_LOW: u8               = 0x0D;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// The command for setting the upper byte of the cursor's linear location.
 | 
					 | 
				
			||||||
const REG_CURSOR_LOCATION_HIGH: u8            = 0x0E;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// The command for setting the lower byte of the cursor's linear location.
 | 
					 | 
				
			||||||
const REG_CURSOR_LOCATION_LOW: u8             = 0x0F;
 | 
					 | 
				
			||||||
const REG_VERTICAL_RETRACE_START: u8          = 0x10;
 | 
					 | 
				
			||||||
const REG_VERTICAL_RETRACE_END: u8            = 0x11;
 | 
					 | 
				
			||||||
const REG_VERTICAL_DISPLAY_ENABLE_END: u8     = 0x12;
 | 
					 | 
				
			||||||
const REG_OFFSET: u8                          = 0x13;
 | 
					 | 
				
			||||||
const REG_UNDERLINE_LOCATION: u8              = 0x14;
 | 
					 | 
				
			||||||
const REG_START_VERTICAL_BLINKING: u8         = 0x15;
 | 
					 | 
				
			||||||
const REG_END_VERTICAL_BLINKING: u8           = 0x16;
 | 
					 | 
				
			||||||
const REG_CRT_MODE_CONTROL: u8                = 0x17;
 | 
					 | 
				
			||||||
const REG_LINE_COMPARE: u8                    = 0x18;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Other VGA registers.
 | 
				
			||||||
 | 
					pub const REG_VERTICAL_RETRACE_START: u8          = 0x10;
 | 
				
			||||||
 | 
					pub const REG_VERTICAL_RETRACE_END: u8            = 0x11;
 | 
				
			||||||
 | 
					pub const REG_VERTICAL_DISPLAY_ENABLE_END: u8     = 0x12;
 | 
				
			||||||
 | 
					pub const REG_OFFSET: u8                          = 0x13;
 | 
				
			||||||
 | 
					pub const REG_UNDERLINE_LOCATION: u8              = 0x14;
 | 
				
			||||||
 | 
					pub const REG_START_VERTICAL_BLINKING: u8         = 0x15;
 | 
				
			||||||
 | 
					pub const REG_END_VERTICAL_BLINKING: u8           = 0x16;
 | 
				
			||||||
 | 
					pub const REG_CRT_MODE_CONTROL: u8                = 0x17;
 | 
				
			||||||
 | 
					pub const REG_LINE_COMPARE: u8                    = 0x18;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// The start of the cursor scan line, the very beginning.
 | 
					/// The start of the cursor scan line, the very beginning.
 | 
				
			||||||
const CURSOR_SCANLINE_START: u8   = 0x0;
 | 
					pub const CURSOR_SCANLINE_START: u8   = 0x0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// The scan line for use in the underline cursor shape.
 | 
					/// The scan line for use in the underline cursor shape.
 | 
				
			||||||
const CURSOR_SCANLINE_MIDDLE: u8  = 0xE;
 | 
					pub const CURSOR_SCANLINE_MIDDLE: u8  = 0xE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// The end of the cursor scan line, the very end.
 | 
					/// The end of the cursor scan line, the very end.
 | 
				
			||||||
const CURSOR_SCANLINE_END: u8     = 0xF;
 | 
					pub const CURSOR_SCANLINE_END: u8     = 0xF;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// If set, disables the cursor.
 | 
					/// If set, disables the cursor.
 | 
				
			||||||
const CURSOR_DISABLE: u8    = 0x20;
 | 
					pub const CURSOR_DISABLE: u8    = 0x20;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// The number of characters wide the screen is.
 | 
				
			||||||
pub const WIDTH: u16        = 80;
 | 
					pub const WIDTH: u16        = 80;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// The number of characters heigh the screen is.
 | 
				
			||||||
pub const HEIGHT: u16       = 25;
 | 
					pub const HEIGHT: u16       = 25;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// The set of colours that VGA supports and can display for the foreground and background.
 | 
					/// The set of colours that VGA supports and can display for the foreground and background.
 | 
				
			||||||
pub const COLOUR_BLACK: u4            = 0x00;
 | 
					pub const COLOUR_BLACK: u4            = 0x00;
 | 
				
			||||||
pub const COLOUR_BLUE: u4             = 0x01;
 | 
					pub const COLOUR_BLUE: u4             = 0x01;
 | 
				
			||||||
pub const COLOUR_GREEN: u4            = 0x02;
 | 
					pub const COLOUR_GREEN: u4            = 0x02;
 | 
				
			||||||
| 
						 | 
					@ -83,7 +77,7 @@ pub const COLOUR_LIGHT_BROWN: u4      = 0x0E;
 | 
				
			||||||
pub const COLOUR_WHITE: u4            = 0x0F;
 | 
					pub const COLOUR_WHITE: u4            = 0x0F;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// The set of shapes that can be displayed.
 | 
					/// The set of shapes that can be displayed.
 | 
				
			||||||
pub const CursorShape = enum(u1) {
 | 
					pub const CursorShape = enum {
 | 
				
			||||||
    /// The cursor has the underline shape.
 | 
					    /// The cursor has the underline shape.
 | 
				
			||||||
    UNDERLINE,
 | 
					    UNDERLINE,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -97,6 +91,28 @@ var cursor_scanline_start: u8 = undefined;
 | 
				
			||||||
/// The cursor scan line end so to know whether is in block or underline mode.
 | 
					/// The cursor scan line end so to know whether is in block or underline mode.
 | 
				
			||||||
var cursor_scanline_end: u8 = undefined;
 | 
					var cursor_scanline_end: u8 = undefined;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// A inline function for setting the VGA register port to read from or write to.
 | 
				
			||||||
 | 
					inline fn sendPort(port: u8) void {
 | 
				
			||||||
 | 
					    arch.outb(PORT_ADDRESS, port);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// A inline function for sending data to the set VGA register port.
 | 
				
			||||||
 | 
					inline fn sendData(data: u8) void {
 | 
				
			||||||
 | 
					    arch.outb(PORT_DATA, data);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// A inline function for setting the VGA register port to read from or write toa and sending data
 | 
				
			||||||
 | 
					/// to the set VGA register port.
 | 
				
			||||||
 | 
					inline fn sendPortData(port: u8, data: u8) void {
 | 
				
			||||||
 | 
					    sendPort(port);
 | 
				
			||||||
 | 
					    sendData(data);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// A inline function for getting data from a set VGA register port.
 | 
				
			||||||
 | 
					inline fn getData() u8 {
 | 
				
			||||||
 | 
					    return arch.inb(PORT_DATA);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// Takes two 4 bit values that represent the foreground and background colour of the text and
 | 
					/// Takes two 4 bit values that represent the foreground and background colour of the text and
 | 
				
			||||||
/// returns a 8 bit value that gives both to be displayed.
 | 
					/// returns a 8 bit value that gives both to be displayed.
 | 
				
			||||||
| 
						 | 
					@ -105,7 +121,7 @@ var cursor_scanline_end: u8 = undefined;
 | 
				
			||||||
///     IN fg: u4 - The foreground colour.
 | 
					///     IN fg: u4 - The foreground colour.
 | 
				
			||||||
///     IN bg: u4 - The background colour.
 | 
					///     IN bg: u4 - The background colour.
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// Return:
 | 
					/// Return: u8
 | 
				
			||||||
///     Both combined into 1 byte for the colour to be displayed.
 | 
					///     Both combined into 1 byte for the colour to be displayed.
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
pub fn entryColour(fg: u4, bg: u4) u8 {
 | 
					pub fn entryColour(fg: u4, bg: u4) u8 {
 | 
				
			||||||
| 
						 | 
					@ -117,30 +133,25 @@ pub fn entryColour(fg: u4, bg: u4) u8 {
 | 
				
			||||||
/// background colour.
 | 
					/// background colour.
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// Arguments:
 | 
					/// Arguments:
 | 
				
			||||||
///     IN uc: u8     - The character.
 | 
					///     IN char: u8   - The character ro display.
 | 
				
			||||||
///     IN colour: u8 - The foreground and background colour.
 | 
					///     IN colour: u8 - The foreground and background colour.
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// Return:
 | 
					/// Return: u16
 | 
				
			||||||
///     The VGA entry.
 | 
					///     A VGA entry.
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
pub fn entry(uc: u8, colour: u8) u16 {
 | 
					pub fn entry(char: u8, colour: u8) u16 {
 | 
				
			||||||
    return u16(uc) | u16(colour) << 8;
 | 
					    return u16(char) | u16(colour) << 8;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// Update the hardware on screen cursor.
 | 
					/// Update the hardware on screen cursor.
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// Arguments:
 | 
					/// Arguments:
 | 
				
			||||||
///     IN x: u16 - The horizontal position of the cursor.
 | 
					///     IN x: u16 - The horizontal position of the cursor (column).
 | 
				
			||||||
///     IN y: u16 - The vertical position of the cursor.
 | 
					///     IN y: u16 - The vertical position of the cursor (row).
 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// Return:
 | 
					 | 
				
			||||||
///     The VGA entry.
 | 
					 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
pub fn updateCursor(x: u16, y: u16) void {
 | 
					pub fn updateCursor(x: u16, y: u16) void {
 | 
				
			||||||
    var pos: u16 = undefined;
 | 
					    var pos: u16 = undefined;
 | 
				
			||||||
    var pos_upper: u16 = undefined;
 | 
					 | 
				
			||||||
    var pos_lower: u16 = undefined;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Make sure new cursor position is within the screen
 | 
					    // Make sure new cursor position is within the screen
 | 
				
			||||||
    if (x < WIDTH and y < HEIGHT) {
 | 
					    if (x < WIDTH and y < HEIGHT) {
 | 
				
			||||||
| 
						 | 
					@ -150,31 +161,28 @@ pub fn updateCursor(x: u16, y: u16) void {
 | 
				
			||||||
        pos = (HEIGHT - 1) * WIDTH + (WIDTH - 1);
 | 
					        pos = (HEIGHT - 1) * WIDTH + (WIDTH - 1);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pos_upper = (pos >> 8) & 0x00FF;
 | 
					    const pos_upper = (pos >> 8) & 0x00FF;
 | 
				
			||||||
    pos_lower = pos & 0x00FF;
 | 
					    const pos_lower = pos & 0x00FF;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Set the cursor position
 | 
					    // Set the cursor position
 | 
				
			||||||
    arch.outb(PORT_ADDRESS, REG_CURSOR_LOCATION_LOW);
 | 
					    sendPortData(REG_CURSOR_LOCATION_LOW, @truncate(u8, pos_lower));
 | 
				
			||||||
    arch.outb(PORT_DATA, @truncate(u8, pos_lower));
 | 
					    sendPortData(REG_CURSOR_LOCATION_HIGH, @truncate(u8, pos_upper));
 | 
				
			||||||
 | 
					 | 
				
			||||||
    arch.outb(PORT_ADDRESS, REG_CURSOR_LOCATION_HIGH);
 | 
					 | 
				
			||||||
    arch.outb(PORT_DATA, @truncate(u8, pos_upper));
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// Get the hardware cursor position.
 | 
					/// Get the linear position of the hardware cursor.
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// Return:
 | 
					/// Return: u16
 | 
				
			||||||
///     The linear cursor position.
 | 
					///     The linear cursor position.
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
pub fn getCursor() u16 {
 | 
					pub fn getCursor() u16 {
 | 
				
			||||||
    var cursor: u16 = 0;
 | 
					    var cursor: u16 = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    arch.outb(PORT_ADDRESS, REG_CURSOR_LOCATION_LOW);
 | 
					    sendPort(REG_CURSOR_LOCATION_LOW);
 | 
				
			||||||
    cursor |= u16(arch.inb(PORT_DATA));
 | 
					    cursor |= u16(getData());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    arch.outb(PORT_ADDRESS, REG_CURSOR_LOCATION_HIGH);
 | 
					    sendPort(REG_CURSOR_LOCATION_HIGH);
 | 
				
			||||||
    cursor |= u16(arch.inb(PORT_DATA)) << 8;
 | 
					    cursor |= u16(getData()) << 8;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return cursor;
 | 
					    return cursor;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -183,50 +191,37 @@ pub fn getCursor() u16 {
 | 
				
			||||||
/// Enables the blinking cursor to that is is visible.
 | 
					/// Enables the blinking cursor to that is is visible.
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
pub fn enableCursor() void {
 | 
					pub fn enableCursor() void {
 | 
				
			||||||
    arch.outb(PORT_ADDRESS, REG_CURSOR_START);
 | 
					    sendPortData(REG_CURSOR_START, cursor_scanline_start);
 | 
				
			||||||
    arch.outb(PORT_DATA, cursor_scanline_start);
 | 
					    sendPortData(REG_CURSOR_END, cursor_scanline_end);
 | 
				
			||||||
 | 
					 | 
				
			||||||
    arch.outb(PORT_ADDRESS, REG_CURSOR_END);
 | 
					 | 
				
			||||||
    arch.outb(PORT_DATA, cursor_scanline_end);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// Disables the blinking cursor to that is is visible.
 | 
					/// Disables the blinking cursor to that is is visible.
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
pub fn disableCursor() void {
 | 
					pub fn disableCursor() void {
 | 
				
			||||||
    arch.outb(PORT_ADDRESS, REG_CURSOR_START);
 | 
					    sendPortData(REG_CURSOR_START, CURSOR_DISABLE);
 | 
				
			||||||
    arch.outb(PORT_DATA, CURSOR_DISABLE);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// Set the shape of the cursor. This can be and underline or block shape.
 | 
					/// Set the shape of the cursor. This can be and underline or block shape.
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// Arguments:
 | 
					/// Arguments:
 | 
				
			||||||
///     IN shape: CURSOR_SHAPE - The enum CURSOR_SHAPE that selects which shape to use.
 | 
					///     IN shape: CursorShape - The enum CursorShape that selects which shape to use.
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
pub fn setCursorShape(shape: CursorShape) void {
 | 
					pub fn setCursorShape(shape: CursorShape) void {
 | 
				
			||||||
    switch (shape) {
 | 
					    switch (shape) {
 | 
				
			||||||
        CursorShape.UNDERLINE => {
 | 
					        CursorShape.UNDERLINE => {
 | 
				
			||||||
            arch.outb(PORT_ADDRESS, REG_CURSOR_START);
 | 
					 | 
				
			||||||
            arch.outb(PORT_DATA, CURSOR_SCANLINE_MIDDLE);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            arch.outb(PORT_ADDRESS, REG_CURSOR_END);
 | 
					 | 
				
			||||||
            arch.outb(PORT_DATA, CURSOR_SCANLINE_END);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            cursor_scanline_start = CURSOR_SCANLINE_MIDDLE;
 | 
					            cursor_scanline_start = CURSOR_SCANLINE_MIDDLE;
 | 
				
			||||||
            cursor_scanline_end = CURSOR_SCANLINE_END;
 | 
					            cursor_scanline_end = CURSOR_SCANLINE_END;
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        CursorShape.BLOCK => {
 | 
					        CursorShape.BLOCK => {
 | 
				
			||||||
            arch.outb(PORT_ADDRESS, REG_CURSOR_START);
 | 
					 | 
				
			||||||
            arch.outb(PORT_DATA, CURSOR_SCANLINE_START);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            arch.outb(PORT_ADDRESS, REG_CURSOR_END);
 | 
					 | 
				
			||||||
            arch.outb(PORT_DATA, CURSOR_SCANLINE_END);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            cursor_scanline_start = CURSOR_SCANLINE_START;
 | 
					            cursor_scanline_start = CURSOR_SCANLINE_START;
 | 
				
			||||||
            cursor_scanline_end = CURSOR_SCANLINE_END;
 | 
					            cursor_scanline_end = CURSOR_SCANLINE_END;
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sendPortData(REG_CURSOR_START, cursor_scanline_start);
 | 
				
			||||||
 | 
					    sendPortData(REG_CURSOR_END, cursor_scanline_end);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
| 
						 | 
					@ -234,176 +229,8 @@ pub fn setCursorShape(shape: CursorShape) void {
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
pub fn init() void {
 | 
					pub fn init() void {
 | 
				
			||||||
    // Set the maximum scan line to 0x0F
 | 
					    // Set the maximum scan line to 0x0F
 | 
				
			||||||
    arch.outb(PORT_ADDRESS, REG_MAXIMUM_SCAN_LINE);
 | 
					    sendPortData(REG_MAXIMUM_SCAN_LINE, CURSOR_SCANLINE_END);
 | 
				
			||||||
    arch.outb(PORT_DATA, CURSOR_SCANLINE_END);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Set by default the underline cursor
 | 
					    // Set by default the underline cursor
 | 
				
			||||||
    setCursorShape(CursorShape.UNDERLINE);
 | 
					    setCursorShape(CursorShape.UNDERLINE);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
test "entryColour" {
 | 
					 | 
				
			||||||
    var fg: u4 = COLOUR_BLACK;
 | 
					 | 
				
			||||||
    var bg: u4 = COLOUR_BLACK;
 | 
					 | 
				
			||||||
    var res: u8 = entryColour(fg, bg);
 | 
					 | 
				
			||||||
    expectEqual(u8(0x00), res);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fg = COLOUR_LIGHT_GREEN;
 | 
					 | 
				
			||||||
    bg = COLOUR_BLACK;
 | 
					 | 
				
			||||||
    res = entryColour(fg, bg);
 | 
					 | 
				
			||||||
    expectEqual(u8(0x0A), res);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fg = COLOUR_BLACK;
 | 
					 | 
				
			||||||
    bg = COLOUR_LIGHT_GREEN;
 | 
					 | 
				
			||||||
    res = entryColour(fg, bg);
 | 
					 | 
				
			||||||
    expectEqual(u8(0xA0), res);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fg = COLOUR_BROWN;
 | 
					 | 
				
			||||||
    bg = COLOUR_LIGHT_GREEN;
 | 
					 | 
				
			||||||
    res = entryColour(fg, bg);
 | 
					 | 
				
			||||||
    expectEqual(u8(0xA6), res);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
test "entry" {
 | 
					 | 
				
			||||||
    var colour: u8 = entryColour(COLOUR_BROWN, COLOUR_LIGHT_GREEN);
 | 
					 | 
				
			||||||
    expectEqual(u8(0xA6), colour);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Character '0' is 0x30
 | 
					 | 
				
			||||||
    var video_entry: u16 = entry('0', colour);
 | 
					 | 
				
			||||||
    expectEqual(u16(0xA630), video_entry);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    video_entry = entry(0x55, colour);
 | 
					 | 
				
			||||||
    expectEqual(u16(0xA655), video_entry);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
fn testOutOfBounds(x: u16, y: u16) bool {
 | 
					 | 
				
			||||||
    if (x < HEIGHT and y < WIDTH) {
 | 
					 | 
				
			||||||
        return true;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return false;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
fn testUpperVal(x: u16, y: u16) u16 {
 | 
					 | 
				
			||||||
    const pos: u16 = x * WIDTH + y;
 | 
					 | 
				
			||||||
    const pos_upper: u16 = (pos >> 8) & 0x00FF;
 | 
					 | 
				
			||||||
    return pos_upper;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
fn testLowerVal(x: u16, y: u16) u16 {
 | 
					 | 
				
			||||||
    const pos: u16 = x * WIDTH + y;
 | 
					 | 
				
			||||||
    const pos_lower: u16 = pos & 0x00FF;
 | 
					 | 
				
			||||||
    return pos_lower;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
test "updateCursor out of bounds" {
 | 
					 | 
				
			||||||
    var x: u16 = 0;
 | 
					 | 
				
			||||||
    var y: u16 = 0;
 | 
					 | 
				
			||||||
    var res: bool = testOutOfBounds(x, y);
 | 
					 | 
				
			||||||
    expectEqual(true, res);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    x = HEIGHT - 1;
 | 
					 | 
				
			||||||
    res = testOutOfBounds(x, y);
 | 
					 | 
				
			||||||
    expectEqual(true, res);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    y = WIDTH - 1;
 | 
					 | 
				
			||||||
    res = testOutOfBounds(x, y);
 | 
					 | 
				
			||||||
    expectEqual(true, res);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    x = HEIGHT;
 | 
					 | 
				
			||||||
    y = WIDTH;
 | 
					 | 
				
			||||||
    res = testOutOfBounds(x, y);
 | 
					 | 
				
			||||||
    expectEqual(false, res);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    x = HEIGHT - 1;
 | 
					 | 
				
			||||||
    y = WIDTH;
 | 
					 | 
				
			||||||
    res = testOutOfBounds(x, y);
 | 
					 | 
				
			||||||
    expectEqual(false, res);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    x = HEIGHT;
 | 
					 | 
				
			||||||
    y = WIDTH - 1;
 | 
					 | 
				
			||||||
    res = testOutOfBounds(x, y);
 | 
					 | 
				
			||||||
    expectEqual(false, res);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
test "updateCursor lower values" {
 | 
					 | 
				
			||||||
    var x: u16 = 0x0000;
 | 
					 | 
				
			||||||
    var y: u16 = 0x0000;
 | 
					 | 
				
			||||||
    var res: u16 = testLowerVal(x, y);
 | 
					 | 
				
			||||||
    var expected: u16 = 0x0000;
 | 
					 | 
				
			||||||
    expectEqual(expected, res);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    x = 0x0000;
 | 
					 | 
				
			||||||
    y = 0x000A;
 | 
					 | 
				
			||||||
    res = testLowerVal(x, y);
 | 
					 | 
				
			||||||
    expected = 0x000A;
 | 
					 | 
				
			||||||
    expectEqual(expected, res);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    x = 0x000A;
 | 
					 | 
				
			||||||
    y = 0x0000;
 | 
					 | 
				
			||||||
    res = testLowerVal(x, y);
 | 
					 | 
				
			||||||
    expected = 0x0020;
 | 
					 | 
				
			||||||
    expectEqual(expected, res);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    x = 0x000A;
 | 
					 | 
				
			||||||
    y = 0x000A;
 | 
					 | 
				
			||||||
    res = testLowerVal(x, y);
 | 
					 | 
				
			||||||
    expected = 0x002A;
 | 
					 | 
				
			||||||
    expectEqual(expected, res);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
test "updateCursor upper values" {
 | 
					 | 
				
			||||||
    var x: u16 = 0x0000;
 | 
					 | 
				
			||||||
    var y: u16 = 0x0000;
 | 
					 | 
				
			||||||
    var res: u16 = testUpperVal(x, y);
 | 
					 | 
				
			||||||
    var expected: u16 = 0x0000;
 | 
					 | 
				
			||||||
    expectEqual(expected, res);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    x = 0x0000;
 | 
					 | 
				
			||||||
    y = 0x000A;
 | 
					 | 
				
			||||||
    res = testUpperVal(x, y);
 | 
					 | 
				
			||||||
    expected = 0x0000;
 | 
					 | 
				
			||||||
    expectEqual(expected, res);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    x = 0x000A;
 | 
					 | 
				
			||||||
    y = 0x0000;
 | 
					 | 
				
			||||||
    res = testUpperVal(x, y);
 | 
					 | 
				
			||||||
    expected = 0x0003;
 | 
					 | 
				
			||||||
    expectEqual(expected, res);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    x = 0x000A;
 | 
					 | 
				
			||||||
    y = 0x000A;
 | 
					 | 
				
			||||||
    res = testUpperVal(x, y);
 | 
					 | 
				
			||||||
    expected = 0x0003;
 | 
					 | 
				
			||||||
    expectEqual(expected, res);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
test "getCursor all" {
 | 
					 | 
				
			||||||
    warn(" Waiting for mocking ");
 | 
					 | 
				
			||||||
    var res = getCursor();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
test "enableCursor all" {
 | 
					 | 
				
			||||||
    warn(" Waiting for mocking ");
 | 
					 | 
				
			||||||
    enableCursor();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
test "disableCursor all" {
 | 
					 | 
				
			||||||
    warn(" Waiting for mocking ");
 | 
					 | 
				
			||||||
    disableCursor();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
test "setCursorShape all" {
 | 
					 | 
				
			||||||
    setCursorShape(CursorShape.UNDERLINE);
 | 
					 | 
				
			||||||
    expectEqual(CURSOR_SCANLINE_MIDDLE, cursor_scanline_start);
 | 
					 | 
				
			||||||
    expectEqual(CURSOR_SCANLINE_END, cursor_scanline_end);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    setCursorShape(CursorShape.BLOCK);
 | 
					 | 
				
			||||||
    expectEqual(CURSOR_SCANLINE_START, cursor_scanline_start);
 | 
					 | 
				
			||||||
    expectEqual(CURSOR_SCANLINE_END, cursor_scanline_end);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
test "init all" {
 | 
					 | 
				
			||||||
    warn(" Waiting for mocking ");
 | 
					 | 
				
			||||||
    init();
 | 
					 | 
				
			||||||
    expectEqual(CURSOR_SCANLINE_MIDDLE, cursor_scanline_start);
 | 
					 | 
				
			||||||
    expectEqual(CURSOR_SCANLINE_END, cursor_scanline_end);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,41 +0,0 @@
 | 
				
			||||||
// Zig version: 0.4.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// Initialise the architecture
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
pub fn init() void {}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// Inline assembly to write to a given port with a byte of data.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// Arguments:
 | 
					 | 
				
			||||||
///     IN port: u16 - The port to write to.
 | 
					 | 
				
			||||||
///     IN data: u8  - The byte of data that will be sent.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
pub fn outb(port: u16, data: u8) void {}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// Inline assembly that reads data from a given port and returns its value.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// Arguments:
 | 
					 | 
				
			||||||
///     IN port: u16 - The port to read data from.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// Return:
 | 
					 | 
				
			||||||
///     The data that the port returns.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
pub fn inb(port: u16) u8 {return 0;}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// A simple way of waiting for I/O event to happen by doing an I/O event to flush the I/O
 | 
					 | 
				
			||||||
/// event being waited.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
pub fn ioWait() void {}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// Register an interrupt handler. The interrupt number should be the arch-specific number.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// Arguments:
 | 
					 | 
				
			||||||
///     IN int: u16 - The arch-specific interrupt number to register for.
 | 
					 | 
				
			||||||
///     IN handler: fn (ctx: *InterruptContext) void - The handler to assign to the interrupt.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
pub fn registerInterruptHandler(int: u16, ctx: fn (ctx: *InterruptContext) void) void {}
 | 
					 | 
				
			||||||
							
								
								
									
										94
									
								
								test/mock/kernel/arch_mock.zig
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								test/mock/kernel/arch_mock.zig
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,94 @@
 | 
				
			||||||
 | 
					const std = @import("std");
 | 
				
			||||||
 | 
					const MemProfile = @import("mem_mock.zig").MemProfile;
 | 
				
			||||||
 | 
					const expect = std.testing.expect;
 | 
				
			||||||
 | 
					const warn = std.debug.warn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const mock_framework = @import("mock_framework.zig");
 | 
				
			||||||
 | 
					pub const initTest = mock_framework.initTest;
 | 
				
			||||||
 | 
					pub const freeTest = mock_framework.freeTest;
 | 
				
			||||||
 | 
					pub const addTestParams = mock_framework.addTestParams;
 | 
				
			||||||
 | 
					pub const addConsumeFunction = mock_framework.addConsumeFunction;
 | 
				
			||||||
 | 
					pub const addRepeatFunction = mock_framework.addRepeatFunction;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub const InterruptContext = struct {
 | 
				
			||||||
 | 
					    // Extra segments
 | 
				
			||||||
 | 
					    gs: u32,
 | 
				
			||||||
 | 
					    fs: u32,
 | 
				
			||||||
 | 
					    es: u32,
 | 
				
			||||||
 | 
					    ds: u32,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Destination, source, base pointer
 | 
				
			||||||
 | 
					    edi: u32,
 | 
				
			||||||
 | 
					    esi: u32,
 | 
				
			||||||
 | 
					    ebp: u32,
 | 
				
			||||||
 | 
					    esp: u32,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // General registers
 | 
				
			||||||
 | 
					    ebx: u32,
 | 
				
			||||||
 | 
					    edx: u32,
 | 
				
			||||||
 | 
					    ecx: u32,
 | 
				
			||||||
 | 
					    eax: u32,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Interrupt number and error code
 | 
				
			||||||
 | 
					    int_num: u32,
 | 
				
			||||||
 | 
					    error_code: u32,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Instruction pointer, code segment and flags
 | 
				
			||||||
 | 
					    eip: u32,
 | 
				
			||||||
 | 
					    cs: u32,
 | 
				
			||||||
 | 
					    eflags: u32,
 | 
				
			||||||
 | 
					    user_esp: u32,
 | 
				
			||||||
 | 
					    ss: u32,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn init(mem_profile: *const MemProfile, allocator: *std.mem.Allocator, comptime options: type) void {
 | 
				
			||||||
 | 
					    //return mock_framework.performAction("init", void, mem_profile, allocator);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn outb(port: u16, data: u8) void {
 | 
				
			||||||
 | 
					    return mock_framework.performAction("outb", void, port, data);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn inb(port: u16) u8 {
 | 
				
			||||||
 | 
					    return mock_framework.performAction("inb", u8, port);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn ioWait() void {
 | 
				
			||||||
 | 
					    return mock_framework.performAction("ioWait", void);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn registerInterruptHandler(int: u16, ctx: fn (ctx: *InterruptContext) void) void {
 | 
				
			||||||
 | 
					    return mock_framework.performAction("registerInterruptHandler", void, int, ctx);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn lgdt(gdt_ptr: *const gdt.GdtPtr) void {
 | 
				
			||||||
 | 
					    return mock_framework.performAction("lgdt", void, gdt_ptr.*);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn ltr() void {
 | 
				
			||||||
 | 
					    return mock_framework.performAction("ltr", void);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn lidt(idt_ptr: *const idt.IdtPtr) void {
 | 
				
			||||||
 | 
					    return mock_framework.performAction("lidt", void, idt_ptr.*);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn enableInterrupts() void {
 | 
				
			||||||
 | 
					    return mock_framework.performAction("enableInterrupts", void);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn disableInterrupts() void {
 | 
				
			||||||
 | 
					    return mock_framework.performAction("disableInterrupts", void);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn halt() void {
 | 
				
			||||||
 | 
					    return mock_framework.performAction("halt", void);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn spinWait() noreturn {
 | 
				
			||||||
 | 
					    while (true) {}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn haltNoInterrupts() noreturn {
 | 
				
			||||||
 | 
					    while (true) {}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										50
									
								
								test/mock/kernel/log_mock.zig
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								test/mock/kernel/log_mock.zig
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,50 @@
 | 
				
			||||||
 | 
					const mock_framework = @import("mock_framework.zig");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub const Level = enum {
 | 
				
			||||||
 | 
					    INFO,
 | 
				
			||||||
 | 
					    DEBUG,
 | 
				
			||||||
 | 
					    WARNING,
 | 
				
			||||||
 | 
					    ERROR
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn logCallback(context: void, str: []const u8) anyerror!void {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn log(comptime level: Level, comptime format: []const u8, args: ...) void {
 | 
				
			||||||
 | 
					    //return mock_framework.performAction("log", void, level, format, args);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn logInfo(comptime format: []const u8, args: ...) void {
 | 
				
			||||||
 | 
					    //return mock_framework.performAction("logInfo", void, format, args);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn logDebug(comptime format: []const u8, args: ...) void {
 | 
				
			||||||
 | 
					    //return mock_framework.performAction("logDebug", void, format, args);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn logWarning(comptime format: []const u8, args: ...) void {
 | 
				
			||||||
 | 
					    //return mock_framework.performAction("logWarning", void, format, args);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn logError(comptime format: []const u8, args: ...) void {
 | 
				
			||||||
 | 
					    //return mock_framework.performAction("logError", void, format, args);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn addRepeatFunction(comptime fun_name: []const u8, function: var) void {
 | 
				
			||||||
 | 
					    mock_framework.addRepeatFunction(fun_name, function);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn addTestFunction(comptime fun_name: []const u8, function: var) void {
 | 
				
			||||||
 | 
					    mock_framework.addRepeatFunction(fun_name, function);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn addTestParams(comptime fun_name: []const u8, params: ...) void {
 | 
				
			||||||
 | 
					    mock_framework.addTestParams(fun_name, params);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn initTest() void {
 | 
				
			||||||
 | 
					    mock_framework.initTest();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn freeTest() void {
 | 
				
			||||||
 | 
					    mock_framework.freeTest();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										32
									
								
								test/mock/kernel/mem_mock.zig
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								test/mock/kernel/mem_mock.zig
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,32 @@
 | 
				
			||||||
 | 
					const multiboot = @import("../../../src/kernel/multiboot.zig");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub const MemProfile = struct {
 | 
				
			||||||
 | 
					    vaddr_end: [*]u8,
 | 
				
			||||||
 | 
					    vaddr_start: [*]u8,
 | 
				
			||||||
 | 
					    physaddr_end: [*]u8,
 | 
				
			||||||
 | 
					    physaddr_start: [*]u8,
 | 
				
			||||||
 | 
					    mem_kb: u32,
 | 
				
			||||||
 | 
					    fixed_alloc_size: u32
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// The virtual/physical start/end of the kernel code
 | 
				
			||||||
 | 
					var KERNEL_PHYSADDR_START: u32 = 0x00100000;
 | 
				
			||||||
 | 
					var KERNEL_PHYSADDR_END: u32 = 0x01000000;
 | 
				
			||||||
 | 
					var KERNEL_VADDR_START: u32 = 0xC0100000;
 | 
				
			||||||
 | 
					var KERNEL_VADDR_END: u32 = 0xC1100000;
 | 
				
			||||||
 | 
					var KERNEL_ADDR_OFFSET: u32 = 0xC0000000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// The size of the fixed allocator used before the heap is set up. Set to 1MiB.
 | 
				
			||||||
 | 
					const FIXED_ALLOC_SIZE = 1024 * 1024;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn init(mb_info: *multiboot.multiboot_info_t) MemProfile {
 | 
				
			||||||
 | 
					    return MemProfile{
 | 
				
			||||||
 | 
					        .vaddr_end = @ptrCast([*]u8, &KERNEL_VADDR_END),
 | 
				
			||||||
 | 
					        .vaddr_start = @ptrCast([*]u8, &KERNEL_VADDR_START),
 | 
				
			||||||
 | 
					        .physaddr_end = @ptrCast([*]u8, &KERNEL_PHYSADDR_END),
 | 
				
			||||||
 | 
					        .physaddr_start = @ptrCast([*]u8, &KERNEL_PHYSADDR_START),
 | 
				
			||||||
 | 
					        // Total memory available including the initial 1MiB that grub doesn't include
 | 
				
			||||||
 | 
					        .mem_kb = mb_info.mem_upper + mb_info.mem_lower + 1024,
 | 
				
			||||||
 | 
					        .fixed_alloc_size = FIXED_ALLOC_SIZE
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										589
									
								
								test/mock/kernel/mock_framework.zig
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										589
									
								
								test/mock/kernel/mock_framework.zig
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,589 @@
 | 
				
			||||||
 | 
					const std = @import("std");
 | 
				
			||||||
 | 
					const builtin = @import("builtin");
 | 
				
			||||||
 | 
					const StringHashMap = std.StringHashMap;
 | 
				
			||||||
 | 
					const expect = std.testing.expect;
 | 
				
			||||||
 | 
					const expectEqual = std.testing.expectEqual;
 | 
				
			||||||
 | 
					const GlobalAllocator = std.debug.global_allocator;
 | 
				
			||||||
 | 
					const TailQueue = std.TailQueue;
 | 
				
			||||||
 | 
					const warn = std.debug.warn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// The enumeration of types that the mocking framework supports. These include basic types like u8
 | 
				
			||||||
 | 
					/// and function types like fn () void
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					const DataElementType = enum {
 | 
				
			||||||
 | 
					    U4,
 | 
				
			||||||
 | 
					    U8,
 | 
				
			||||||
 | 
					    U16,
 | 
				
			||||||
 | 
					    U32,
 | 
				
			||||||
 | 
					    FN_OVOID,
 | 
				
			||||||
 | 
					    FN_OUSIZE,
 | 
				
			||||||
 | 
					    FN_OU16,
 | 
				
			||||||
 | 
					    FN_IU16_OU8,
 | 
				
			||||||
 | 
					    FN_IU4_IU4_OU8,
 | 
				
			||||||
 | 
					    FN_IU8_IU8_OU16,
 | 
				
			||||||
 | 
					    FN_IU16_IU8_OVOID,
 | 
				
			||||||
 | 
					    FN_IU16_IU16_OVOID,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// A tagged union of all the data elements that the mocking framework can work with. This can be
 | 
				
			||||||
 | 
					/// expanded to add new types. This is needed as need a list of data that all have different types,
 | 
				
			||||||
 | 
					/// so this wraps the data into a union, (which is of one type) so can have a list of them.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					const DataElement = union(DataElementType) {
 | 
				
			||||||
 | 
					    U4: u4,
 | 
				
			||||||
 | 
					    U8: u8,
 | 
				
			||||||
 | 
					    U16: u16,
 | 
				
			||||||
 | 
					    U32: u32,
 | 
				
			||||||
 | 
					    FN_OVOID: fn () void,
 | 
				
			||||||
 | 
					    FN_OUSIZE: fn () usize,
 | 
				
			||||||
 | 
					    FN_OU16: fn () u16,
 | 
				
			||||||
 | 
					    FN_IU16_OU8: fn (u16) u8,
 | 
				
			||||||
 | 
					    FN_IU4_IU4_OU8: fn (u4, u4) u8,
 | 
				
			||||||
 | 
					    FN_IU8_IU8_OU16: fn (u8, u8) u16,
 | 
				
			||||||
 | 
					    FN_IU16_IU8_OVOID: fn (u16, u8) void,
 | 
				
			||||||
 | 
					    FN_IU16_IU16_OVOID: fn (u16, u16) void,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// The type of actions that the mocking framework can perform.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					const ActionType = enum {
 | 
				
			||||||
 | 
					    /// This will test the parameters passed to a function. It will test the correct types and
 | 
				
			||||||
 | 
					    /// value of each parameter. This is also used to return a specific value from a function so
 | 
				
			||||||
 | 
					    /// can test for returns from a function.
 | 
				
			||||||
 | 
					    TestValue,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// This action is to replace a function call to be mocked with another function the user
 | 
				
			||||||
 | 
					    /// chooses to be replaced. This will consume the function call. This will allow the user to
 | 
				
			||||||
 | 
					    /// check that the function is called once or multiple times by added a function to be mocked
 | 
				
			||||||
 | 
					    /// multiple times. This also allows the ability for a function to be mocked by different
 | 
				
			||||||
 | 
					    /// functions each time it is called.
 | 
				
			||||||
 | 
					    ConsumeFunctionCall,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// This is similar to the ConsumeFunctionCall action, but will call the mocked function
 | 
				
			||||||
 | 
					    /// repeatedly until the mocking is done.
 | 
				
			||||||
 | 
					    RepeatFunctionCall,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Other actions that could be used
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // This will check that a function isn't called.
 | 
				
			||||||
 | 
					    //NoFunctionCall
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // This is a generalisation of ConsumeFunctionCall and RepeatFunctionCall but can specify how
 | 
				
			||||||
 | 
					    // many times a function can be called.
 | 
				
			||||||
 | 
					    //FunctionCallN
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// This is a pair of action and data to be actioned on.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					const Action = struct {
 | 
				
			||||||
 | 
					    action: ActionType,
 | 
				
			||||||
 | 
					    data: DataElement,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// The type for a queue of actions using std.TailQueue.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					const ActionList = TailQueue(Action);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// The type for linking the function name to be mocked and the action list to be acted on.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					const NamedActionMap = StringHashMap(ActionList);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// The mocking framework.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// Return: type
 | 
				
			||||||
 | 
					///     This returns a struct for adding and acting on mocked functions.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					fn Mock() type {
 | 
				
			||||||
 | 
					    return struct {
 | 
				
			||||||
 | 
					        const Self = @This();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /// The map of function name and action list.
 | 
				
			||||||
 | 
					        named_actions: NamedActionMap,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ///
 | 
				
			||||||
 | 
					        /// Create a DataElement from data. This wraps data into a union. This allows the ability
 | 
				
			||||||
 | 
					        /// to have a list of different types.
 | 
				
			||||||
 | 
					        ///
 | 
				
			||||||
 | 
					        /// Arguments:
 | 
				
			||||||
 | 
					        ///     IN arg: var - The data, this can be a function or basic type value.
 | 
				
			||||||
 | 
					        ///
 | 
				
			||||||
 | 
					        /// Return: DataElement
 | 
				
			||||||
 | 
					        ///     A DataElement with the data wrapped.
 | 
				
			||||||
 | 
					        ///
 | 
				
			||||||
 | 
					        fn createDataElement(arg: var) DataElement {
 | 
				
			||||||
 | 
					            return switch (@typeOf(arg)) {
 | 
				
			||||||
 | 
					                u4 => DataElement{ .U4 = arg },
 | 
				
			||||||
 | 
					                u8 => DataElement{ .U8 = arg },
 | 
				
			||||||
 | 
					                u16 => DataElement{ .U16 = arg },
 | 
				
			||||||
 | 
					                u32 => DataElement{ .U32 = arg },
 | 
				
			||||||
 | 
					                fn () void => DataElement{ .FN_OVOID = arg },
 | 
				
			||||||
 | 
					                fn () usize => DataElement{ .FN_OUSIZE = arg },
 | 
				
			||||||
 | 
					                fn () u16 => DataElement{ .FN_OU16 = arg },
 | 
				
			||||||
 | 
					                fn (u16) u8 => DataElement{ .FN_IU16_OU8 = arg },
 | 
				
			||||||
 | 
					                fn (u4, u4) u8 => DataElement{ .FN_IU4_IU4_OU8 = arg },
 | 
				
			||||||
 | 
					                fn (u8, u8) u16 => DataElement{ .FN_IU8_IU8_OU16 = arg },
 | 
				
			||||||
 | 
					                fn (u16, u8) void => DataElement{ .FN_IU16_IU8_OVOID = arg },
 | 
				
			||||||
 | 
					                fn (u16, u16) void => DataElement{ .FN_IU16_IU16_OVOID = arg },
 | 
				
			||||||
 | 
					                else => @compileError("Type not supported: " ++ @typeName(@typeOf(arg))),
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ///
 | 
				
			||||||
 | 
					        /// Get the enum that represents the type given.
 | 
				
			||||||
 | 
					        ///
 | 
				
			||||||
 | 
					        /// Arguments:
 | 
				
			||||||
 | 
					        ///     IN T: type - A type.
 | 
				
			||||||
 | 
					        ///
 | 
				
			||||||
 | 
					        /// Return: DataElementType
 | 
				
			||||||
 | 
					        ///     The DataElementType that represents the type given.
 | 
				
			||||||
 | 
					        ///
 | 
				
			||||||
 | 
					        fn getDataElementType(comptime T: type) DataElementType {
 | 
				
			||||||
 | 
					            return switch (T) {
 | 
				
			||||||
 | 
					                u4 => DataElementType.U4,
 | 
				
			||||||
 | 
					                u8 => DataElementType.U8,
 | 
				
			||||||
 | 
					                u16 => DataElementType.U16,
 | 
				
			||||||
 | 
					                u32 => DataElementType.U32,
 | 
				
			||||||
 | 
					                fn () void => DataElementType.FN_OVOID,
 | 
				
			||||||
 | 
					                fn () u16 => DataElementType.FN_OU16,
 | 
				
			||||||
 | 
					                fn (u16) u8 => DataElementType.FN_IU16_OU8,
 | 
				
			||||||
 | 
					                fn (u4, u4) u8 => DataElementType.FN_IU4_IU4_OU8,
 | 
				
			||||||
 | 
					                fn (u8, u8) u16 => DataElementType.FN_IU8_IU8_OU16,
 | 
				
			||||||
 | 
					                fn (u16, u8) void => DataElementType.FN_IU16_IU8_OVOID,
 | 
				
			||||||
 | 
					                fn (u16, u16) void => DataElementType.FN_IU16_IU16_OVOID,
 | 
				
			||||||
 | 
					                else => @compileError("Type not supported: " ++ @typeName(T)),
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ///
 | 
				
			||||||
 | 
					        /// Get the data out of the tagged union
 | 
				
			||||||
 | 
					        ///
 | 
				
			||||||
 | 
					        /// Arguments:
 | 
				
			||||||
 | 
					        ///     IN T: type              - The type of the data to extract. Used to switch on the
 | 
				
			||||||
 | 
					        ///                               tagged union.
 | 
				
			||||||
 | 
					        ///     IN element: DataElement - The data element to unwrap the data from.
 | 
				
			||||||
 | 
					        ///
 | 
				
			||||||
 | 
					        /// Return: T
 | 
				
			||||||
 | 
					        ///     The data of type T from the DataElement.
 | 
				
			||||||
 | 
					        ///
 | 
				
			||||||
 | 
					        fn getDataValue(comptime T: type, element: DataElement) T {
 | 
				
			||||||
 | 
					            return switch (T) {
 | 
				
			||||||
 | 
					                u4 => element.U4,
 | 
				
			||||||
 | 
					                u8 => element.U8,
 | 
				
			||||||
 | 
					                u16 => element.U16,
 | 
				
			||||||
 | 
					                u32 => element.U32,
 | 
				
			||||||
 | 
					                fn () void => element.FN_OVOID,
 | 
				
			||||||
 | 
					                fn () u16 => element.FN_OU16,
 | 
				
			||||||
 | 
					                fn (u16) u8 => element.FN_IU16_OU8,
 | 
				
			||||||
 | 
					                fn (u4, u4) u8 => element.FN_IU4_IU4_OU8,
 | 
				
			||||||
 | 
					                fn (u8, u8) u16 => element.FN_IU8_IU8_OU16,
 | 
				
			||||||
 | 
					                fn (u16, u8) void => element.FN_IU16_IU8_OVOID,
 | 
				
			||||||
 | 
					                fn (u16, u16) void => element.FN_IU16_IU16_OVOID,
 | 
				
			||||||
 | 
					                else => @compileError("Type not supported: " ++ @typeName(T)),
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ///
 | 
				
			||||||
 | 
					        /// Create a function type from a return type and its arguments. Waiting for
 | 
				
			||||||
 | 
					        /// https://github.com/ziglang/zig/issues/313. TODO: Tidy mocking framework #69
 | 
				
			||||||
 | 
					        ///
 | 
				
			||||||
 | 
					        /// Arguments:
 | 
				
			||||||
 | 
					        ///     IN RetType: type   - The return type of the function.
 | 
				
			||||||
 | 
					        ///     IN params: arglist - The argument list for the function.
 | 
				
			||||||
 | 
					        ///
 | 
				
			||||||
 | 
					        /// Return: type
 | 
				
			||||||
 | 
					        ///     A function type that represents the return type and its arguments.
 | 
				
			||||||
 | 
					        ///
 | 
				
			||||||
 | 
					        fn getFunctionType(comptime RetType: type, params: ...) type {
 | 
				
			||||||
 | 
					            return switch (params.len) {
 | 
				
			||||||
 | 
					                0 => fn () RetType,
 | 
				
			||||||
 | 
					                1 => fn (@typeOf(params[0])) RetType,
 | 
				
			||||||
 | 
					                2 => fn (@typeOf(params[0]), @typeOf(params[1])) RetType,
 | 
				
			||||||
 | 
					                else => @compileError("Couldn't generate function type for " ++ params.len ++ "parameters\n"),
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ///
 | 
				
			||||||
 | 
					        /// This tests a value passed to a function.
 | 
				
			||||||
 | 
					        ///
 | 
				
			||||||
 | 
					        /// Arguments:
 | 
				
			||||||
 | 
					        ///     IN ExpectedType: type           - The expected type of the value to be tested.
 | 
				
			||||||
 | 
					        ///     IN expected_value: ExpectedType - The expected value to be tested. This is what was
 | 
				
			||||||
 | 
					        ///                                       passed to the functions.
 | 
				
			||||||
 | 
					        ///     IN elem: DataElement            - The wrapped data element to test against the
 | 
				
			||||||
 | 
					        ///                                       expected value.
 | 
				
			||||||
 | 
					        ///
 | 
				
			||||||
 | 
					        fn expectTest(comptime ExpectedType: type, expected_value: ExpectedType, elem: DataElement) void {
 | 
				
			||||||
 | 
					            if (ExpectedType == void) {
 | 
				
			||||||
 | 
					                // Can't test void as it has no value
 | 
				
			||||||
 | 
					                warn("Can not test a value for void\n");
 | 
				
			||||||
 | 
					                expect(false);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Test that the types match
 | 
				
			||||||
 | 
					            const expect_type = comptime getDataElementType(ExpectedType);
 | 
				
			||||||
 | 
					            expectEqual(expect_type, DataElementType(elem));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Types match, so can use the expected type to get the actual data
 | 
				
			||||||
 | 
					            const actual_value = getDataValue(ExpectedType, elem);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Test the values
 | 
				
			||||||
 | 
					            expectEqual(expected_value, actual_value);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ///
 | 
				
			||||||
 | 
					        /// This returns a value from the wrapped data element. This will be a test value to be
 | 
				
			||||||
 | 
					        /// returned by a mocked function.
 | 
				
			||||||
 | 
					        ///
 | 
				
			||||||
 | 
					        /// Arguments:
 | 
				
			||||||
 | 
					        ///     IN fun_name: []const u8         - The function name to be used to tell the user if
 | 
				
			||||||
 | 
					        ///                                       there is no return value set up.
 | 
				
			||||||
 | 
					        ///     IN/OUT action_list: *ActionList - The action list to extract the return value from.
 | 
				
			||||||
 | 
					        ///     IN DataType: type               - The type of the return value.
 | 
				
			||||||
 | 
					        ///
 | 
				
			||||||
 | 
					        fn expectGetValue(comptime fun_name: []const u8, action_list: *ActionList, comptime DataType: type) DataType {
 | 
				
			||||||
 | 
					            if (DataType == void) {
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (action_list.*.popFirst()) |action_node| {
 | 
				
			||||||
 | 
					                const action = action_node.data;
 | 
				
			||||||
 | 
					                const expect_type = getDataElementType(DataType);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                const ret = getDataValue(DataType, action.data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                expectEqual(DataElementType(action.data), expect_type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                // Free the node
 | 
				
			||||||
 | 
					                action_list.*.destroyNode(action_node, GlobalAllocator);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                return ret;
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                warn("No more test values for the return of function: " ++ fun_name ++ "\n");
 | 
				
			||||||
 | 
					                expect(false);
 | 
				
			||||||
 | 
					                unreachable;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ///
 | 
				
			||||||
 | 
					        /// This adds a action to the action list with ActionType provided. It will create a new
 | 
				
			||||||
 | 
					        /// mapping if one doesn't exist for a function name.
 | 
				
			||||||
 | 
					        ///
 | 
				
			||||||
 | 
					        /// Arguments:
 | 
				
			||||||
 | 
					        ///     IN/OUT self: *Self         - Self. This is the mocking object to be modified to add
 | 
				
			||||||
 | 
					        ///                                  the test data.
 | 
				
			||||||
 | 
					        ///     IN fun_name: []const u8    - The function name to add the test parameters to.
 | 
				
			||||||
 | 
					        ///     IN data: var               - The data to add.
 | 
				
			||||||
 | 
					        ///     IN action_type: ActionType - The action type to add.
 | 
				
			||||||
 | 
					        ///
 | 
				
			||||||
 | 
					        pub fn addAction(self: *Self, comptime fun_name: []const u8, data: var, action_type: ActionType) void {
 | 
				
			||||||
 | 
					            // Add a new mapping if one doesn't exist.
 | 
				
			||||||
 | 
					            if (!self.named_actions.contains(fun_name)) {
 | 
				
			||||||
 | 
					                expect(self.named_actions.put(fun_name, TailQueue(Action).init()) catch unreachable == null);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Get the function mapping to add the parameter to.
 | 
				
			||||||
 | 
					            if (self.named_actions.get(fun_name)) |actions_kv| {
 | 
				
			||||||
 | 
					                var action_list = actions_kv.value;
 | 
				
			||||||
 | 
					                const action = Action{
 | 
				
			||||||
 | 
					                    .action = action_type,
 | 
				
			||||||
 | 
					                    .data = createDataElement(data),
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					                var a = action_list.createNode(action, GlobalAllocator) catch unreachable;
 | 
				
			||||||
 | 
					                action_list.append(a);
 | 
				
			||||||
 | 
					                // Need to re-assign the value as it isn't updated when we just append
 | 
				
			||||||
 | 
					                actions_kv.value = action_list;
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                // Shouldn't get here as we would have just added a new mapping
 | 
				
			||||||
 | 
					                // But just in case ;)
 | 
				
			||||||
 | 
					                warn("No function name: " ++ fun_name ++ "\n");
 | 
				
			||||||
 | 
					                expect(false);
 | 
				
			||||||
 | 
					                unreachable;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ///
 | 
				
			||||||
 | 
					        /// Perform an action on a function. This can be one of ActionType.
 | 
				
			||||||
 | 
					        ///
 | 
				
			||||||
 | 
					        /// Arguments:
 | 
				
			||||||
 | 
					        ///     IN/OUT self: *Self      - Self. This is the mocking object to be modified to
 | 
				
			||||||
 | 
					        ///                               perform a action.
 | 
				
			||||||
 | 
					        ///     IN fun_name: []const u8 - The function name to act on.
 | 
				
			||||||
 | 
					        ///     IN RetType: type        - The return type of the function being mocked.
 | 
				
			||||||
 | 
					        ///     IN params: arglist      - The list of parameters of the mocked function.
 | 
				
			||||||
 | 
					        ///
 | 
				
			||||||
 | 
					        /// Return: RetType
 | 
				
			||||||
 | 
					        ///     The return value of the mocked function. This can be void.
 | 
				
			||||||
 | 
					        ///
 | 
				
			||||||
 | 
					        pub fn performAction(self: *Self, comptime fun_name: []const u8, comptime RetType: type, params: ...) RetType {
 | 
				
			||||||
 | 
					            if (self.named_actions.get(fun_name)) |kv_actions_list| {
 | 
				
			||||||
 | 
					                var action_list = kv_actions_list.value;
 | 
				
			||||||
 | 
					                // Peak the first action to test the action type
 | 
				
			||||||
 | 
					                if (action_list.first) |action_node| {
 | 
				
			||||||
 | 
					                    const action = action_node.data;
 | 
				
			||||||
 | 
					                    const ret = switch (action.action) {
 | 
				
			||||||
 | 
					                        ActionType.TestValue => ret: {
 | 
				
			||||||
 | 
					                            comptime var i = 0;
 | 
				
			||||||
 | 
					                            inline while (i < params.len) : (i += 1) {
 | 
				
			||||||
 | 
					                                // Now pop the action as we are going to use it
 | 
				
			||||||
 | 
					                                // Have already checked that it is not null
 | 
				
			||||||
 | 
					                                const test_node = action_list.popFirst().?;
 | 
				
			||||||
 | 
					                                const test_action = test_node.data;
 | 
				
			||||||
 | 
					                                const param = params[i];
 | 
				
			||||||
 | 
					                                const param_type = @typeOf(params[i]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                expectTest(param_type, param, test_action.data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                // Free the node
 | 
				
			||||||
 | 
					                                action_list.destroyNode(test_node, GlobalAllocator);
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                            break :ret expectGetValue(fun_name, &action_list, RetType);
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                        ActionType.ConsumeFunctionCall => ret: {
 | 
				
			||||||
 | 
					                            // Now pop the action as we are going to use it
 | 
				
			||||||
 | 
					                            // Have already checked that it is not null
 | 
				
			||||||
 | 
					                            const test_node = action_list.popFirst().?;
 | 
				
			||||||
 | 
					                            const test_element = test_node.data.data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            // Work out the type of the function to call from the params and return type
 | 
				
			||||||
 | 
					                            // At compile time
 | 
				
			||||||
 | 
					                            //const expected_function = getFunctionType(RetType, params);
 | 
				
			||||||
 | 
					                            // Waiting for this:
 | 
				
			||||||
 | 
					                            // error: compiler bug: unable to call var args function at compile time. https://github.com/ziglang/zig/issues/313
 | 
				
			||||||
 | 
					                            // to be resolved
 | 
				
			||||||
 | 
					                            const expected_function = switch (params.len) {
 | 
				
			||||||
 | 
					                                0 => fn () RetType,
 | 
				
			||||||
 | 
					                                1 => fn (@typeOf(params[0])) RetType,
 | 
				
			||||||
 | 
					                                2 => fn (@typeOf(params[0]), @typeOf(params[1])) RetType,
 | 
				
			||||||
 | 
					                                else => @compileError("Couldn't generate function type for " ++ params.len ++ "parameters\n"),
 | 
				
			||||||
 | 
					                            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            // Get the corresponding DataElementType
 | 
				
			||||||
 | 
					                            const expect_type = comptime getDataElementType(expected_function);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            // Test that the types match
 | 
				
			||||||
 | 
					                            expectEqual(expect_type, DataElementType(test_element));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            // Types match, so can use the expected type to get the actual data
 | 
				
			||||||
 | 
					                            const actual_function = getDataValue(expected_function, test_element);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            // Free the node
 | 
				
			||||||
 | 
					                            action_list.destroyNode(test_node, GlobalAllocator);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            // The data element will contain the function to call
 | 
				
			||||||
 | 
					                            const r = switch (params.len) {
 | 
				
			||||||
 | 
					                                0 => @noInlineCall(actual_function),
 | 
				
			||||||
 | 
					                                1 => @noInlineCall(actual_function, params[0]),
 | 
				
			||||||
 | 
					                                2 => @noInlineCall(actual_function, params[0], params[1]),
 | 
				
			||||||
 | 
					                                else => @compileError(params.len ++ " or more parameters not supported"),
 | 
				
			||||||
 | 
					                            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            break :ret r;
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                        ActionType.RepeatFunctionCall => ret: {
 | 
				
			||||||
 | 
					                            // Do the same for ActionType.ConsumeFunctionCall but instead of
 | 
				
			||||||
 | 
					                            // popping the function, just peak
 | 
				
			||||||
 | 
					                            const test_element = action.data;
 | 
				
			||||||
 | 
					                            const expected_function = switch (params.len) {
 | 
				
			||||||
 | 
					                                0 => fn () RetType,
 | 
				
			||||||
 | 
					                                1 => fn (@typeOf(params[0])) RetType,
 | 
				
			||||||
 | 
					                                2 => fn (@typeOf(params[0]), @typeOf(params[1])) RetType,
 | 
				
			||||||
 | 
					                                else => @compileError("Couldn't generate function type for " ++ params.len ++ "parameters\n"),
 | 
				
			||||||
 | 
					                            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            // Get the corresponding DataElementType
 | 
				
			||||||
 | 
					                            const expect_type = comptime getDataElementType(expected_function);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            // Test that the types match
 | 
				
			||||||
 | 
					                            expectEqual(expect_type, DataElementType(test_element));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            // Types match, so can use the expected type to get the actual data
 | 
				
			||||||
 | 
					                            const actual_function = getDataValue(expected_function, test_element);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            // The data element will contain the function to call
 | 
				
			||||||
 | 
					                            const r = switch (params.len) {
 | 
				
			||||||
 | 
					                                0 => @noInlineCall(actual_function),
 | 
				
			||||||
 | 
					                                1 => @noInlineCall(actual_function, params[0]),
 | 
				
			||||||
 | 
					                                2 => @noInlineCall(actual_function, params[0], params[1]),
 | 
				
			||||||
 | 
					                                else => @compileError(params.len ++ " or more parameters not supported"),
 | 
				
			||||||
 | 
					                            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            break :ret r;
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    // Re-assign the action list as this would have changed
 | 
				
			||||||
 | 
					                    kv_actions_list.value = action_list;
 | 
				
			||||||
 | 
					                    return ret;
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    warn("No action list elements for function: " ++ fun_name ++ "\n");
 | 
				
			||||||
 | 
					                    expect(false);
 | 
				
			||||||
 | 
					                    unreachable;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                warn("No function name: " ++ fun_name ++ "\n");
 | 
				
			||||||
 | 
					                expect(false);
 | 
				
			||||||
 | 
					                unreachable;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ///
 | 
				
			||||||
 | 
					        /// Initialise the mocking framework.
 | 
				
			||||||
 | 
					        ///
 | 
				
			||||||
 | 
					        /// Return: Self
 | 
				
			||||||
 | 
					        ///     An initialised mocking framework.
 | 
				
			||||||
 | 
					        ///
 | 
				
			||||||
 | 
					        pub fn init() Self {
 | 
				
			||||||
 | 
					            return Self{
 | 
				
			||||||
 | 
					                .named_actions = StringHashMap(ActionList).init(GlobalAllocator),
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ///
 | 
				
			||||||
 | 
					        /// End the mocking session. This will check all test parameters and consume functions are
 | 
				
			||||||
 | 
					        /// consumed. Any repeat functions are deinit.
 | 
				
			||||||
 | 
					        ///
 | 
				
			||||||
 | 
					        /// Arguments:
 | 
				
			||||||
 | 
					        ///     IN/OUT self: *Self - Self. This is the mocking object to be modified to finished
 | 
				
			||||||
 | 
					        ///                          the mocking session.
 | 
				
			||||||
 | 
					        ///
 | 
				
			||||||
 | 
					        pub fn finish(self: *Self) void {
 | 
				
			||||||
 | 
					            // Make sure the expected list is empty
 | 
				
			||||||
 | 
					            var it = self.named_actions.iterator();
 | 
				
			||||||
 | 
					            while (it.next()) |next| {
 | 
				
			||||||
 | 
					                var action_list = next.value;
 | 
				
			||||||
 | 
					                if (action_list.popFirst()) |action_node| {
 | 
				
			||||||
 | 
					                    const action = action_node.data;
 | 
				
			||||||
 | 
					                    switch (action.action) {
 | 
				
			||||||
 | 
					                        ActionType.TestValue, ActionType.ConsumeFunctionCall => {
 | 
				
			||||||
 | 
					                            // These need to be all consumed
 | 
				
			||||||
 | 
					                            warn("Unused testing value: Type: {}, value: {} for function '{}'\n", action.action, DataElementType(action.data), next.key);
 | 
				
			||||||
 | 
					                            expect(false);
 | 
				
			||||||
 | 
					                            unreachable;
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                        ActionType.RepeatFunctionCall => {
 | 
				
			||||||
 | 
					                            // As this is a repeat action, the function will still be here
 | 
				
			||||||
 | 
					                            // So need to free it
 | 
				
			||||||
 | 
					                            action_list.destroyNode(action_node, GlobalAllocator);
 | 
				
			||||||
 | 
					                            next.value = action_list;
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Free the function mapping
 | 
				
			||||||
 | 
					            self.named_actions.deinit();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// The global mocking object that is used for a mocking session. Maybe in the future, we can have
 | 
				
			||||||
 | 
					/// local mocking objects so can run the tests in parallel.
 | 
				
			||||||
 | 
					var mock: ?Mock() = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// Get the mocking object and check we have one initialised.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// Return: *Mock()
 | 
				
			||||||
 | 
					///     Pointer to the global mocking object so can be modified.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					fn getMockObject() *Mock() {
 | 
				
			||||||
 | 
					    // Make sure we have a mock object
 | 
				
			||||||
 | 
					    if (mock) |*m| {
 | 
				
			||||||
 | 
					        return m;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        warn("MOCK object doesn't exists, please initiate this test\n");
 | 
				
			||||||
 | 
					        expect(false);
 | 
				
			||||||
 | 
					        unreachable;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// Initialise the mocking framework.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					pub fn initTest() void {
 | 
				
			||||||
 | 
					    // Make sure there isn't a mock object
 | 
				
			||||||
 | 
					    if (mock) |_| {
 | 
				
			||||||
 | 
					        warn("MOCK object already exists, please free previous test\n");
 | 
				
			||||||
 | 
					        expect(false);
 | 
				
			||||||
 | 
					        unreachable;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        mock = Mock().init();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// End the mocking session. This will check all test parameters and consume functions are
 | 
				
			||||||
 | 
					/// consumed. Any repeat functions are deinit.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					pub fn freeTest() void {
 | 
				
			||||||
 | 
					    getMockObject().finish();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // This will stop double frees
 | 
				
			||||||
 | 
					    mock = null;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// Add a list of test parameters to the action list. This will create a list of data
 | 
				
			||||||
 | 
					/// elements that represent the list of parameters that will be passed to a mocked
 | 
				
			||||||
 | 
					/// function. A mocked function may be called multiple times, so this list may contain
 | 
				
			||||||
 | 
					/// multiple values for each call to the same mocked function.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// Arguments:
 | 
				
			||||||
 | 
					///     IN/OUT self: *Self      - Self. This is the mocking object to be modified to add
 | 
				
			||||||
 | 
					///                               the test parameters.
 | 
				
			||||||
 | 
					///     IN fun_name: []const u8 - The function name to add the test parameters to.
 | 
				
			||||||
 | 
					///     IN params: arglist      - The parameters to add.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					pub fn addTestParams(comptime fun_name: []const u8, params: ...) void {
 | 
				
			||||||
 | 
					    var mock_obj = getMockObject();
 | 
				
			||||||
 | 
					    comptime var i = 0;
 | 
				
			||||||
 | 
					    inline while (i < params.len) : (i += 1) {
 | 
				
			||||||
 | 
					        mock_obj.addAction(fun_name, params[i], ActionType.TestValue);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// Add a function to mock out another. This will add a consume function action, so once
 | 
				
			||||||
 | 
					/// the mocked function is called, this action wil be removed.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// Arguments:
 | 
				
			||||||
 | 
					///     IN fun_name: []const u8 - The function name to add the function to.
 | 
				
			||||||
 | 
					///     IN function: var        - The function to add.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					pub fn addConsumeFunction(comptime fun_name: []const u8, function: var) void {
 | 
				
			||||||
 | 
					    getMockObject().addAction(fun_name, function, ActionType.ConsumeFunctionCall);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// Add a function to mock out another. This will add a repeat function action, so once
 | 
				
			||||||
 | 
					/// the mocked function is called, this action wil be removed.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// Arguments:
 | 
				
			||||||
 | 
					///     IN fun_name: []const u8 - The function name to add the function to.
 | 
				
			||||||
 | 
					///     IN function: var        - The function to add.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					pub fn addRepeatFunction(comptime fun_name: []const u8, function: var) void {
 | 
				
			||||||
 | 
					    getMockObject().addAction(fun_name, function, ActionType.RepeatFunctionCall);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// Perform an action on a function. This can be one of ActionType.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// Arguments:
 | 
				
			||||||
 | 
					///     IN fun_name: []const u8 - The function name to act on.
 | 
				
			||||||
 | 
					///     IN RetType: type        - The return type of the function being mocked.
 | 
				
			||||||
 | 
					///     IN params: arglist      - The list of parameters of the mocked function.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// Return: RetType
 | 
				
			||||||
 | 
					///     The return value of the mocked function. This can be void.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					pub fn performAction(comptime fun_name: []const u8, comptime RetType: type, params: ...) RetType {
 | 
				
			||||||
 | 
					    return getMockObject().performAction(fun_name, RetType, params);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										5
									
								
								test/mock/kernel/mocking.zig
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								test/mock/kernel/mocking.zig
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,5 @@
 | 
				
			||||||
 | 
					pub const log = @import("log_mock.zig");
 | 
				
			||||||
 | 
					pub const mem = @import("mem_mock.zig");
 | 
				
			||||||
 | 
					pub const vga = @import("vga_mock.zig");
 | 
				
			||||||
 | 
					pub const arch = @import("arch_mock.zig");
 | 
				
			||||||
 | 
					pub const panic = @import("panic_mock.zig");
 | 
				
			||||||
							
								
								
									
										7
									
								
								test/mock/kernel/panic_mock.zig
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								test/mock/kernel/panic_mock.zig
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,7 @@
 | 
				
			||||||
 | 
					const builtin = @import("builtin");
 | 
				
			||||||
 | 
					const panic = @import("std").debug.panic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn panicFmt(trace: ?*builtin.StackTrace, comptime format: []const u8, args: ...) noreturn {
 | 
				
			||||||
 | 
					    @setCold(true);
 | 
				
			||||||
 | 
					    panic(format, args);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										88
									
								
								test/mock/kernel/vga_mock.zig
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								test/mock/kernel/vga_mock.zig
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,88 @@
 | 
				
			||||||
 | 
					const std = @import("std");
 | 
				
			||||||
 | 
					const expect = std.testing.expect;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const arch = @import("arch.zig").internals;
 | 
				
			||||||
 | 
					const mock_framework = @import("mock_framework.zig");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub const initTest = mock_framework.initTest;
 | 
				
			||||||
 | 
					pub const freeTest = mock_framework.freeTest;
 | 
				
			||||||
 | 
					pub const addTestParams = mock_framework.addTestParams;
 | 
				
			||||||
 | 
					pub const addConsumeFunction = mock_framework.addConsumeFunction;
 | 
				
			||||||
 | 
					pub const addRepeatFunction = mock_framework.addRepeatFunction;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub const WIDTH: u16 = 80;
 | 
				
			||||||
 | 
					pub const HEIGHT: u16 = 25;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub const COLOUR_BLACK: u4 = 0x00;
 | 
				
			||||||
 | 
					pub const COLOUR_BLUE: u4 = 0x01;
 | 
				
			||||||
 | 
					pub const COLOUR_GREEN: u4 = 0x02;
 | 
				
			||||||
 | 
					pub const COLOUR_CYAN: u4 = 0x03;
 | 
				
			||||||
 | 
					pub const COLOUR_RED: u4 = 0x04;
 | 
				
			||||||
 | 
					pub const COLOUR_MAGENTA: u4 = 0x05;
 | 
				
			||||||
 | 
					pub const COLOUR_BROWN: u4 = 0x06;
 | 
				
			||||||
 | 
					pub const COLOUR_LIGHT_GREY: u4 = 0x07;
 | 
				
			||||||
 | 
					pub const COLOUR_DARK_GREY: u4 = 0x08;
 | 
				
			||||||
 | 
					pub const COLOUR_LIGHT_BLUE: u4 = 0x09;
 | 
				
			||||||
 | 
					pub const COLOUR_LIGHT_GREEN: u4 = 0x0A;
 | 
				
			||||||
 | 
					pub const COLOUR_LIGHT_CYAN: u4 = 0x0B;
 | 
				
			||||||
 | 
					pub const COLOUR_LIGHT_RED: u4 = 0x0C;
 | 
				
			||||||
 | 
					pub const COLOUR_LIGHT_MAGENTA: u4 = 0x0D;
 | 
				
			||||||
 | 
					pub const COLOUR_LIGHT_BROWN: u4 = 0x0E;
 | 
				
			||||||
 | 
					pub const COLOUR_WHITE: u4 = 0x0F;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub const CursorShape = enum {
 | 
				
			||||||
 | 
					    UNDERLINE,
 | 
				
			||||||
 | 
					    BLOCK,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn entryColour(fg: u4, bg: u4) u8 {
 | 
				
			||||||
 | 
					    return mock_framework.performAction("entryColour", u8, fg, bg);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn entry(uc: u8, colour: u8) u16 {
 | 
				
			||||||
 | 
					    return mock_framework.performAction("entry", u16, uc, colour);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn updateCursor(x: u16, y: u16) void {
 | 
				
			||||||
 | 
					    return mock_framework.performAction("updateCursor", void, x, y);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn getCursor() u16 {
 | 
				
			||||||
 | 
					    return mock_framework.performAction("getCursor", u16);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn enableCursor() void {
 | 
				
			||||||
 | 
					    return mock_framework.performAction("enableCursor", void);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn disableCursor() void {
 | 
				
			||||||
 | 
					    return mock_framework.performAction("disableCursor", void);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn setCursorShape(shape: CursorShape) void {
 | 
				
			||||||
 | 
					    return mock_framework.performAction("setCursorShape", void, shape);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn init() void {
 | 
				
			||||||
 | 
					    return mock_framework.performAction("init", void);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// User defined mocked functions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn mock_entryColour(fg: u4, bg: u4) u8 {
 | 
				
			||||||
 | 
					    return u8(fg) | u8(bg) << 4;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn mock_entry(uc: u8, c: u8) u16 {
 | 
				
			||||||
 | 
					    return u16(uc) | u16(c) << 8;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn mock_updateCursor(x: u16, y: u16) void {
 | 
				
			||||||
 | 
					    // Here we can do any testing we like with the parameters. e.g. test out of bounds
 | 
				
			||||||
 | 
					    expect(x < WIDTH);
 | 
				
			||||||
 | 
					    expect(y < HEIGHT);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn mock_enableCursor() void {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn mock_disableCursor() void {}
 | 
				
			||||||
							
								
								
									
										4
									
								
								test/unittests/kernel/test_tty.zig
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								test/unittests/kernel/test_tty.zig
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,4 @@
 | 
				
			||||||
 | 
					// I gave up on trying to get all the tests in a separate file for the tty
 | 
				
			||||||
 | 
					test "" {
 | 
				
			||||||
 | 
					    _ = @import("../../../src/kernel/tty.zig");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										293
									
								
								test/unittests/kernel/test_vga.zig
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										293
									
								
								test/unittests/kernel/test_vga.zig
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,293 @@
 | 
				
			||||||
 | 
					const vga = @import("../../../src/kernel/vga.zig");
 | 
				
			||||||
 | 
					const arch = @import("../../../src/kernel/arch.zig").internals;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const expectEqual = @import("std").testing.expectEqual;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test "entryColour" {
 | 
				
			||||||
 | 
					    var fg: u4 = vga.COLOUR_BLACK;
 | 
				
			||||||
 | 
					    var bg: u4 = vga.COLOUR_BLACK;
 | 
				
			||||||
 | 
					    var res: u8 = vga.entryColour(fg, bg);
 | 
				
			||||||
 | 
					    expectEqual(u8(0x00), res);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fg = vga.COLOUR_LIGHT_GREEN;
 | 
				
			||||||
 | 
					    bg = vga.COLOUR_BLACK;
 | 
				
			||||||
 | 
					    res = vga.entryColour(fg, bg);
 | 
				
			||||||
 | 
					    expectEqual(u8(0x0A), res);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fg = vga.COLOUR_BLACK;
 | 
				
			||||||
 | 
					    bg = vga.COLOUR_LIGHT_GREEN;
 | 
				
			||||||
 | 
					    res = vga.entryColour(fg, bg);
 | 
				
			||||||
 | 
					    expectEqual(u8(0xA0), res);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fg = vga.COLOUR_BROWN;
 | 
				
			||||||
 | 
					    bg = vga.COLOUR_LIGHT_GREEN;
 | 
				
			||||||
 | 
					    res = vga.entryColour(fg, bg);
 | 
				
			||||||
 | 
					    expectEqual(u8(0xA6), res);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test "entry" {
 | 
				
			||||||
 | 
					    var colour: u8 = vga.entryColour(vga.COLOUR_BROWN, vga.COLOUR_LIGHT_GREEN);
 | 
				
			||||||
 | 
					    expectEqual(u8(0xA6), colour);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Character '0' is 0x30
 | 
				
			||||||
 | 
					    var video_entry: u16 = vga.entry('0', colour);
 | 
				
			||||||
 | 
					    expectEqual(u16(0xA630), video_entry);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    video_entry = vga.entry(0x55, colour);
 | 
				
			||||||
 | 
					    expectEqual(u16(0xA655), video_entry);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test "updateCursor width out of bounds" {
 | 
				
			||||||
 | 
					    const x: u16 = vga.WIDTH;
 | 
				
			||||||
 | 
					    const y: u16 = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const max_cursor: u16 = (vga.HEIGHT - 1) * vga.WIDTH + (vga.WIDTH - 1);
 | 
				
			||||||
 | 
					    const expected_upper: u8 = @truncate(u8, (max_cursor >> 8) & 0x00FF);
 | 
				
			||||||
 | 
					    const expected_lower: u8 = @truncate(u8, max_cursor & 0x00FF);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    arch.initTest();
 | 
				
			||||||
 | 
					    defer arch.freeTest();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Mocking out the arch.outb calls for changing the hardware cursor:
 | 
				
			||||||
 | 
					    arch.addTestParams("outb",
 | 
				
			||||||
 | 
					        vga.PORT_ADDRESS, vga.REG_CURSOR_LOCATION_LOW,
 | 
				
			||||||
 | 
					        vga.PORT_DATA, expected_lower,
 | 
				
			||||||
 | 
					        vga.PORT_ADDRESS, vga.REG_CURSOR_LOCATION_HIGH,
 | 
				
			||||||
 | 
					        vga.PORT_DATA, expected_upper);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    vga.updateCursor(x, y);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test "updateCursor height out of bounds" {
 | 
				
			||||||
 | 
					    const x: u16 = 0;
 | 
				
			||||||
 | 
					    const y: u16 = vga.HEIGHT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const max_cursor: u16 = (vga.HEIGHT - 1) * vga.WIDTH + (vga.WIDTH - 1);
 | 
				
			||||||
 | 
					    const expected_upper: u8 = @truncate(u8, (max_cursor >> 8) & 0x00FF);
 | 
				
			||||||
 | 
					    const expected_lower: u8 = @truncate(u8, max_cursor & 0x00FF);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    arch.initTest();
 | 
				
			||||||
 | 
					    defer arch.freeTest();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Mocking out the arch.outb calls for changing the hardware cursor:
 | 
				
			||||||
 | 
					    arch.addTestParams("outb",
 | 
				
			||||||
 | 
					        vga.PORT_ADDRESS, vga.REG_CURSOR_LOCATION_LOW,
 | 
				
			||||||
 | 
					        vga.PORT_DATA, expected_lower,
 | 
				
			||||||
 | 
					        vga.PORT_ADDRESS, vga.REG_CURSOR_LOCATION_HIGH,
 | 
				
			||||||
 | 
					        vga.PORT_DATA, expected_upper);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    vga.updateCursor(x, y);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test "updateCursor width and height out of bounds" {
 | 
				
			||||||
 | 
					    const x: u16 = vga.WIDTH;
 | 
				
			||||||
 | 
					    const y: u16 = vga.HEIGHT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const max_cursor: u16 = (vga.HEIGHT - 1) * vga.WIDTH + (vga.WIDTH - 1);
 | 
				
			||||||
 | 
					    const expected_upper: u8 = @truncate(u8, (max_cursor >> 8) & 0x00FF);
 | 
				
			||||||
 | 
					    const expected_lower: u8 = @truncate(u8, max_cursor & 0x00FF);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    arch.initTest();
 | 
				
			||||||
 | 
					    defer arch.freeTest();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Mocking out the arch.outb calls for changing the hardware cursor:
 | 
				
			||||||
 | 
					    arch.addTestParams("outb",
 | 
				
			||||||
 | 
					        vga.PORT_ADDRESS, vga.REG_CURSOR_LOCATION_LOW,
 | 
				
			||||||
 | 
					        vga.PORT_DATA, expected_lower,
 | 
				
			||||||
 | 
					        vga.PORT_ADDRESS, vga.REG_CURSOR_LOCATION_HIGH,
 | 
				
			||||||
 | 
					        vga.PORT_DATA, expected_upper);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    vga.updateCursor(x, y);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test "updateCursor width-1 and height out of bounds" {
 | 
				
			||||||
 | 
					    const x: u16 = vga.WIDTH - 1;
 | 
				
			||||||
 | 
					    const y: u16 = vga.HEIGHT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const max_cursor: u16 = (vga.HEIGHT - 1) * vga.WIDTH + (vga.WIDTH - 1);
 | 
				
			||||||
 | 
					    const expected_upper: u8 = @truncate(u8, (max_cursor >> 8) & 0x00FF);
 | 
				
			||||||
 | 
					    const expected_lower: u8 = @truncate(u8, max_cursor & 0x00FF);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    arch.initTest();
 | 
				
			||||||
 | 
					    defer arch.freeTest();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Mocking out the arch.outb calls for changing the hardware cursor:
 | 
				
			||||||
 | 
					    arch.addTestParams("outb",
 | 
				
			||||||
 | 
					        vga.PORT_ADDRESS, vga.REG_CURSOR_LOCATION_LOW,
 | 
				
			||||||
 | 
					        vga.PORT_DATA, expected_lower,
 | 
				
			||||||
 | 
					        vga.PORT_ADDRESS, vga.REG_CURSOR_LOCATION_HIGH,
 | 
				
			||||||
 | 
					        vga.PORT_DATA, expected_upper);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    vga.updateCursor(x, y);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test "updateCursor width and height-1 out of bounds" {
 | 
				
			||||||
 | 
					    const x: u16 = vga.WIDTH;
 | 
				
			||||||
 | 
					    const y: u16 = vga.HEIGHT - 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const max_cursor: u16 = (vga.HEIGHT - 1) * vga.WIDTH + (vga.WIDTH - 1);
 | 
				
			||||||
 | 
					    const expected_upper: u8 = @truncate(u8, (max_cursor >> 8) & 0x00FF);
 | 
				
			||||||
 | 
					    const expected_lower: u8 = @truncate(u8, max_cursor & 0x00FF);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    arch.initTest();
 | 
				
			||||||
 | 
					    defer arch.freeTest();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Mocking out the arch.outb calls for changing the hardware cursor:
 | 
				
			||||||
 | 
					    arch.addTestParams("outb",
 | 
				
			||||||
 | 
					        vga.PORT_ADDRESS, vga.REG_CURSOR_LOCATION_LOW,
 | 
				
			||||||
 | 
					        vga.PORT_DATA, expected_lower,
 | 
				
			||||||
 | 
					        vga.PORT_ADDRESS, vga.REG_CURSOR_LOCATION_HIGH,
 | 
				
			||||||
 | 
					        vga.PORT_DATA, expected_upper);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    vga.updateCursor(x, y);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test "updateCursor in bounds" {
 | 
				
			||||||
 | 
					    var x: u16 = 0x000A;
 | 
				
			||||||
 | 
					    var y: u16 = 0x000A;
 | 
				
			||||||
 | 
					    const expected: u16 = y * vga.WIDTH + x;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var expected_upper: u8 = @truncate(u8, (expected >> 8) & 0x00FF);
 | 
				
			||||||
 | 
					    var expected_lower: u8 = @truncate(u8, expected & 0x00FF);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    arch.initTest();
 | 
				
			||||||
 | 
					    defer arch.freeTest();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Mocking out the arch.outb calls for changing the hardware cursor:
 | 
				
			||||||
 | 
					    arch.addTestParams("outb",
 | 
				
			||||||
 | 
					        vga.PORT_ADDRESS, vga.REG_CURSOR_LOCATION_LOW,
 | 
				
			||||||
 | 
					        vga.PORT_DATA, expected_lower,
 | 
				
			||||||
 | 
					        vga.PORT_ADDRESS, vga.REG_CURSOR_LOCATION_HIGH,
 | 
				
			||||||
 | 
					        vga.PORT_DATA, expected_upper);
 | 
				
			||||||
 | 
					    vga.updateCursor(x, y);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test "getCursor 1: 10" {
 | 
				
			||||||
 | 
					    const expect: u16 = u16(10);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Mocking out the arch.outb and arch.inb calls for getting the hardware cursor:
 | 
				
			||||||
 | 
					    arch.initTest();
 | 
				
			||||||
 | 
					    defer arch.freeTest();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    arch.addTestParams("outb",
 | 
				
			||||||
 | 
					        vga.PORT_ADDRESS, vga.REG_CURSOR_LOCATION_LOW);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    arch.addTestParams("inb",
 | 
				
			||||||
 | 
					        vga.PORT_DATA, u8(10));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    arch.addTestParams("outb",
 | 
				
			||||||
 | 
					        vga.PORT_ADDRESS, vga.REG_CURSOR_LOCATION_HIGH);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    arch.addTestParams("inb",
 | 
				
			||||||
 | 
					        vga.PORT_DATA, u8(0));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const actual: u16 = vga.getCursor();
 | 
				
			||||||
 | 
					    expectEqual(expect, actual);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test "getCursor 2: 0xBEEF" {
 | 
				
			||||||
 | 
					    const expect: u16 = u16(0xBEEF);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Mocking out the arch.outb and arch.inb calls for getting the hardware cursor:
 | 
				
			||||||
 | 
					    arch.initTest();
 | 
				
			||||||
 | 
					    defer arch.freeTest();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    arch.addTestParams("outb",
 | 
				
			||||||
 | 
					        vga.PORT_ADDRESS, vga.REG_CURSOR_LOCATION_LOW);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    arch.addTestParams("inb",
 | 
				
			||||||
 | 
					        vga.PORT_DATA, u8(0xEF));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    arch.addTestParams("outb",
 | 
				
			||||||
 | 
					        vga.PORT_ADDRESS, vga.REG_CURSOR_LOCATION_HIGH);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    arch.addTestParams("inb",
 | 
				
			||||||
 | 
					        vga.PORT_DATA, u8(0xBE));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const actual: u16 = vga.getCursor();
 | 
				
			||||||
 | 
					    expectEqual(expect, actual);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test "enableCursor all" {
 | 
				
			||||||
 | 
					    arch.initTest();
 | 
				
			||||||
 | 
					    defer arch.freeTest();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Need to init the cursor start and end positions, so call the vga.init() to set this up
 | 
				
			||||||
 | 
					    arch.addTestParams("outb",
 | 
				
			||||||
 | 
					        vga.PORT_ADDRESS, vga.REG_MAXIMUM_SCAN_LINE,
 | 
				
			||||||
 | 
					        vga.PORT_DATA, vga.CURSOR_SCANLINE_END,
 | 
				
			||||||
 | 
					        vga.PORT_ADDRESS, vga.REG_CURSOR_START,
 | 
				
			||||||
 | 
					        vga.PORT_DATA, vga.CURSOR_SCANLINE_MIDDLE,
 | 
				
			||||||
 | 
					        vga.PORT_ADDRESS, vga.REG_CURSOR_END,
 | 
				
			||||||
 | 
					        vga.PORT_DATA, vga.CURSOR_SCANLINE_END,
 | 
				
			||||||
 | 
					        // Mocking out the arch.outb calls for enabling the cursor:
 | 
				
			||||||
 | 
					        // These are the default cursor positions from vga.init()
 | 
				
			||||||
 | 
					        vga.PORT_ADDRESS, vga.REG_CURSOR_START,
 | 
				
			||||||
 | 
					        vga.PORT_DATA, vga.CURSOR_SCANLINE_MIDDLE,
 | 
				
			||||||
 | 
					        vga.PORT_ADDRESS, vga.REG_CURSOR_END,
 | 
				
			||||||
 | 
					        vga.PORT_DATA, vga.CURSOR_SCANLINE_END);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    vga.init();
 | 
				
			||||||
 | 
					    vga.enableCursor();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test "disableCursor all" {
 | 
				
			||||||
 | 
					    arch.initTest();
 | 
				
			||||||
 | 
					    defer arch.freeTest();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Mocking out the arch.outb calls for disabling the cursor:
 | 
				
			||||||
 | 
					    arch.addTestParams("outb",
 | 
				
			||||||
 | 
					        vga.PORT_ADDRESS, vga.REG_CURSOR_START,
 | 
				
			||||||
 | 
					        vga.PORT_DATA, vga.CURSOR_DISABLE);
 | 
				
			||||||
 | 
					    vga.disableCursor();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test "setCursorShape UNDERLINE" {
 | 
				
			||||||
 | 
					    arch.initTest();
 | 
				
			||||||
 | 
					    defer arch.freeTest();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Mocking out the arch.outb calls for setting the cursor shape to underline:
 | 
				
			||||||
 | 
					    // This will also check that the scan line variables were set properly as these are using in
 | 
				
			||||||
 | 
					    // the arch.outb call
 | 
				
			||||||
 | 
					    arch.addTestParams("outb",
 | 
				
			||||||
 | 
					        vga.PORT_ADDRESS, vga.REG_CURSOR_START,
 | 
				
			||||||
 | 
					        vga.PORT_DATA, vga.CURSOR_SCANLINE_MIDDLE,
 | 
				
			||||||
 | 
					        vga.PORT_ADDRESS, vga.REG_CURSOR_END,
 | 
				
			||||||
 | 
					        vga.PORT_DATA, vga.CURSOR_SCANLINE_END);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    vga.setCursorShape(vga.CursorShape.UNDERLINE);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test "setCursorShape BLOCK" {
 | 
				
			||||||
 | 
					    arch.initTest();
 | 
				
			||||||
 | 
					    defer arch.freeTest();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Mocking out the arch.outb calls for setting the cursor shape to block:
 | 
				
			||||||
 | 
					    // This will also check that the scan line variables were set properly as these are using in
 | 
				
			||||||
 | 
					    // the arch.outb call
 | 
				
			||||||
 | 
					    arch.addTestParams("outb",
 | 
				
			||||||
 | 
					        vga.PORT_ADDRESS, vga.REG_CURSOR_START,
 | 
				
			||||||
 | 
					        vga.PORT_DATA, vga.CURSOR_SCANLINE_START,
 | 
				
			||||||
 | 
					        vga.PORT_ADDRESS, vga.REG_CURSOR_END,
 | 
				
			||||||
 | 
					        vga.PORT_DATA, vga.CURSOR_SCANLINE_END);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    vga.setCursorShape(vga.CursorShape.BLOCK);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test "init all" {
 | 
				
			||||||
 | 
					    arch.initTest();
 | 
				
			||||||
 | 
					    defer arch.freeTest();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Mocking out the arch.outb calls for setting the cursor max scan line and the shape to block:
 | 
				
			||||||
 | 
					    // This will also check that the scan line variables were set properly as these are using in
 | 
				
			||||||
 | 
					    // the arch.outb call for setting the cursor shape.
 | 
				
			||||||
 | 
					    arch.addTestParams("outb",
 | 
				
			||||||
 | 
					        vga.PORT_ADDRESS, vga.REG_MAXIMUM_SCAN_LINE,
 | 
				
			||||||
 | 
					        vga.PORT_DATA, vga.CURSOR_SCANLINE_END,
 | 
				
			||||||
 | 
					        vga.PORT_ADDRESS, vga.REG_CURSOR_START,
 | 
				
			||||||
 | 
					        vga.PORT_DATA, vga.CURSOR_SCANLINE_MIDDLE,
 | 
				
			||||||
 | 
					        vga.PORT_ADDRESS, vga.REG_CURSOR_END,
 | 
				
			||||||
 | 
					        vga.PORT_DATA, vga.CURSOR_SCANLINE_END);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    vga.init();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										4
									
								
								test/unittests/test_all.zig
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								test/unittests/test_all.zig
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,4 @@
 | 
				
			||||||
 | 
					test "all" {
 | 
				
			||||||
 | 
					    _ = @import("kernel/test_vga.zig");
 | 
				
			||||||
 | 
					    _ = @import("kernel/test_tty.zig");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue