...
Some checks are pending
Rhai Tests / Run Rhai Tests (push) Waiting to run

This commit is contained in:
2025-05-12 06:09:25 +03:00
parent 8285fdb7b9
commit 516d0177e7
73 changed files with 38 additions and 37 deletions

34
src/docs/.gitignore vendored
View File

@@ -1,34 +0,0 @@
# Dependencies
/node_modules
# Production
/build
# Generated files
.docusaurus
.cache-loader
# Misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*
bun.lockb
bun.lock
yarn.lock
build.sh
build_dev.sh
develop.sh
docusaurus.config.ts
sidebars.ts
tsconfig.json

View File

@@ -1,22 +0,0 @@
{
"style": "dark",
"links": [
{
"title": "Web",
"items": [
{
"label": "ThreeFold.io",
"href": "https://threefold.io"
},
{
"href": "https://mycelium.threefold.io/",
"label": "Mycelium Network"
},
{
"href": "https://aibox.threefold.io/",
"label": "AI Box"
}
]
}
]
}

View File

@@ -1,17 +0,0 @@
{
"title": "ThreeFold HeroScript",
"tagline": "ThreeFold HeroScript",
"favicon": "img/favicon.png",
"url": "https://threefold.info",
"url_home": "docs/intro",
"baseUrl": "/heroscript/",
"image": "img/tf_graph.png",
"metadata": {
"description": "Internet Infrastructur for Everyone by Everyone, Everywhere.",
"image": "https://threefold.info/tfgrid4/img/tf_graph.png",
"title": "ThreeFold"
},
"buildDest":["root@info.ourworld.tf:/root/hero/www/info/heroscript"],
"buildDestDev":["root@info.ourworld.tf:/root/hero/www/infodev/heroscript"],
"copyright": "ThreeFold"
}

View File

@@ -1,25 +0,0 @@
{
"title": "",
"logo": {
"alt": "ThreeFold Logo",
"src": "img/logo.svg",
"srcDark": "img/new_logo_tft.png"
},
"items": [
{
"href": "https://threefold.io",
"label": "ThreeFold.io",
"position": "right"
},
{
"href": "https://mycelium.threefold.io/",
"label": "Mycelium Network",
"position": "right"
},
{
"href": "https://aibox.threefold.io/",
"label": "AI Box",
"position": "right"
}
]
}

View File

@@ -1,7 +0,0 @@
---
title: "intro"
sidebar_position: 1
---
# HeroScript

View File

@@ -1,8 +0,0 @@
{
"label": "SAL",
"position": 6,
"link": {
"type": "generated-index",
"description": "Tools to work with operating system."
}
}

View File

@@ -1,239 +0,0 @@
---
title: "build containers"
sidebar_position: 20
hide_title: true
---
# Container Builder
The Buildah module provides functions for working with containers and images using the Buildah tool. Buildah helps you create and manage container images.
## Builder Pattern
The Buildah module now supports a Builder pattern, which provides a more intuitive and flexible way to work with containers and images.
### Creating a Builder
```js
// Create a builder with a name and base image
let builder = bah_new("my-container", "alpine:latest");
// Access builder properties
let container_id = builder.container_id;
let name = builder.name;
let image = builder.image;
```
### Builder Methods
The Builder object provides the following methods:
- `run(command)`: Run a command in the container
- `run_with_isolation(command, isolation)`: Run a command with specified isolation
- `copy(source, dest)`: Copy files into the container
- `add(source, dest)`: Add files into the container
- `commit(image_name)`: Commit the container to an image
- `remove()`: Remove the container
- `reset()`: Remove the container and clear the container_id
- `config(options)`: Configure container metadata
- `set_entrypoint(entrypoint)`: Set the entrypoint for the container
- `set_cmd(cmd)`: Set the default command for the container
- `debug_mode`: Get or set the debug flag (true/false)
- `write_content(content, dest_path)`: Write content to a file in the container
- `read_content(source_path)`: Read content from a file in the container
- `images()`: List images in local storage
- `image_remove(image)`: Remove an image
- `image_pull(image, tls_verify)`: Pull an image from a registry
- `image_push(image, destination, tls_verify)`: Push an image to a registry
- `image_tag(image, new_name)`: Add a tag to an image
- `build(tag, context_dir, file, isolation)`: Build an image from a Dockerfile
- `build(tag, context_dir, file, isolation)`: Build an image from a Dockerfile
### Example
```js
// Create a builder
let builder = bah_new("my-container", "alpine:latest");
// Enable debug mode to see command output
builder.debug_mode = true;
// Reset the builder to remove any existing container
builder.reset();
// Create a new container
builder = bah_new("my-container", "alpine:latest");
// Run a command
let result = builder.run("echo 'Hello from container'");
println(`Command output: ${result.stdout}`);
// Write content directly to a file in the container
let script_content = `#!/bin/sh
echo "Hello from startup script"
`;
builder.write_content(script_content, "/start.sh");
builder.run("chmod +x /start.sh");
// Set the entrypoint for the container
builder.set_entrypoint("/start.sh");
// Add a file
file_write("test_file.txt", "Test content");
builder.add("test_file.txt", "/");
// Commit to an image
builder.commit("my-custom-image:latest");
// Clean up
builder.remove();
delete("test_file.txt");
```
## Image Information
### Image Properties
When working with images, you can access the following information:
- `id`: The unique identifier for the image
- `names`: A list of names/tags for the image
- `name`: The primary name of the image, or `<none>` if the image has no names
- `size`: The size of the image
- `created`: When the image was created
## Builder Methods
### `bah_new(name, image)`
Creates a new Builder object for working with a container.
**Parameters:**
- `name` (string): The name to give the container
- `image` (string): The name or ID of the image to create the container from
**Returns:** A Builder object if successful.
**Example:**
```js
// Create a new Builder
let builder = bah_new("my-container", "alpine:latest");
```
**Notes:**
- If a container with the given name already exists, it will be reused instead of creating a new one
- The Builder object provides methods for working with the container
### `reset()`
Resets a Builder by removing the container and clearing the container_id. This allows you to start fresh with the same Builder object.
**Returns:** Nothing.
**Example:**
```js
// Create a Builder
let builder = bah_new("my-container", "alpine:latest");
// Reset the Builder to remove the container
builder.reset();
// Create a new container with the same name
builder = bah_new("my-container", "alpine:latest");
```
### `debug_mode`
Get or set the debug flag for the Builder. When debug mode is enabled, all buildah commands will output their stdout/stderr, making it easier to debug issues.
**Example:**
```js
// Create a Builder
let builder = bah_new("my-container", "alpine:latest");
// Enable debug mode
builder.debug_mode = true;
// Run a command with debug output
builder.run("echo 'Hello with debug'");
// Disable debug mode
builder.debug_mode = false;
```
### `set_entrypoint(entrypoint)`
Sets the entrypoint for the container. The entrypoint is the command that will be executed when the container starts.
**Parameters:**
- `entrypoint` (string): The entrypoint command
**Returns:** Command result if successful.
**Example:**
```js
// Create a Builder
let builder = bah_new("my-container", "alpine:latest");
// Set the entrypoint
builder.set_entrypoint("/start.sh");
```
### `set_cmd(cmd)`
Sets the default command for the container. This is used as arguments to the entrypoint.
**Parameters:**
- `cmd` (string): The default command
**Returns:** Command result if successful.
**Example:**
```js
// Create a Builder
let builder = bah_new("my-container", "alpine:latest");
// Set the default command
builder.set_cmd("--verbose");
```
### `write_content(content, dest_path)`
Writes content to a file in the container.
**Parameters:**
- `content` (string): The content to write
- `dest_path` (string): The destination path in the container
**Returns:** Command result if successful.
**Example:**
```js
// Create a Builder
let builder = bah_new("my-container", "alpine:latest");
// Write content to a file
let content = "Hello, world!";
builder.write_content(content, "/hello.txt");
```
### `read_content(source_path)`
Reads content from a file in the container.
**Parameters:**
- `source_path` (string): The source path in the container
**Returns:** The file content as a string if successful.
**Example:**
```js
// Create a Builder
let builder = bah_new("my-container", "alpine:latest");
// Write content to a file
builder.write_content("Hello, world!", "/hello.txt");
// Read content from the file
let content = builder.read_content("/hello.txt");
println(content); // Outputs: Hello, world!
```

View File

@@ -1,210 +0,0 @@
---
title: "git"
sidebar_position: 5
hide_title: true
---
# Git
This module provides HeroScript wrappers for the Git functionality in SAL.
> **Note:** The constructor for GitTree has been renamed from `new()` to `gittree_new()` to avoid confusion with other constructors. This makes the interface more explicit and less likely to cause naming conflicts.
## Object-Oriented Design
The Git module follows an object-oriented design with two main classes:
1. **GitTree** - Represents a collection of git repositories under a base path
- Created with `gittree_new(base_path)`
- Methods for listing, finding, and getting repositories
2. **GitRepo** - Represents a single git repository
- Obtained from GitTree's `get()` method
- Methods for common git operations: pull, reset, push, commit
This design allows for a more intuitive and flexible interface, with method chaining for complex operations.
## Creating a GitTree
The GitTree object is the main entry point for git operations. It represents a collection of git repositories under a base path.
```js
// Create a new GitTree with a base path
let git_tree = gittree_new("/root/code");
print(`Created GitTree with base path: /home/user/code`);
```
## Finding Repositories
### List All Repositories
```js
// List all git repositories under the base path
let repos = git_tree.list();
print(`Found ${repos.len()} repositories`);
// Print the repositories
for repo in repos {
print(` - ${repo}`);
}
```
### Find Repositories Matching a Pattern
```js
// Find repositories matching a pattern
// Use a wildcard (*) suffix to find multiple matches
let matching_repos = git_tree.find("my-project*");
print("Matching repositories:");
for repo in matching_repos {
print(` - ${repo}`);
}
// Find a specific repository (must match exactly one)
let specific_repo = git_tree.find("unique-project")[0];
print(`Found specific repository: ${specific_repo}`);
```
## Working with Repositories
### Get Repository Objects
```js
// Get GitRepo objects for repositories matching a pattern
let repos = git_tree.get("my-project*");
print(`Found ${repos.len()} repositories`);
// Get a specific repository
let repo = git_tree.get("unique-project")[0];
print(`Working with repository: ${repo.path()}`);
```
### Clone a Repository
```js
// Clone a repository by URL
// This will clone the repository to the base path of the GitTree
let repos = git_tree.get("https://github.com/username/repo.git");
let repo = repos[0];
print(`Repository cloned to: ${repo.path()}`);
```
### Check for Changes
```js
// Check if a repository has uncommitted changes
let repo = git_tree.get("my-project")[0];
if repo.has_changes() {
print("Repository has uncommitted changes");
} else {
print("Repository is clean");
}
```
## Repository Operations
### Pull Changes
```js
// Pull the latest changes from the remote
// This will fail if there are uncommitted changes
let repo = git_tree.get("my-project")[0];
let result = repo.pull();
print("Repository updated successfully");
```
### Reset Local Changes
```js
// Reset any local changes in the repository
let repo = git_tree.get("my-project")[0];
let result = repo.reset();
print("Repository reset successfully");
```
### Commit Changes
```js
// Commit changes in the repository
let repo = git_tree.get("my-project")[0];
let result = repo.commit("Fix bug in login form");
print("Changes committed successfully");
```
### Push Changes
```js
// Push changes to the remote
let repo = git_tree.get("my-project")[0];
let result = repo.push();
print("Changes pushed successfully");
```
## Method Chaining
The GitRepo methods can be chained together for more complex operations:
```js
// Commit changes and push them to the remote
let repo = git_tree.get("my-project")[0];
let result = repo.commit("Add new feature").push();
print("Changes committed and pushed successfully");
// Reset local changes, pull the latest changes, and commit new changes
let repo = git_tree.get("my-project")[0];
let result = repo.reset().pull().commit("Update dependencies");
print("Repository updated successfully");
```
## Complete Example
```js
// Create a new GitTree
let home_dir = env("HOME");
let git_tree = gittree_new(`${home_dir}/code`);
// Clone a repository
let repos = git_tree.get("https://github.com/username/example-repo.git");
let repo = repos[0];
print(`Cloned repository to: ${repo.path()}`);
// Make some changes (using OS module functions)
let file_path = `${repo.path()}/README.md`;
let content = "# Example Repository\n\nThis is an example repository.";
write_file(file_path, content);
// Commit and push the changes
let result = repo.commit("Update README.md").push();
print("Changes committed and pushed successfully");
// List all repositories
let all_repos = git_tree.list();
print("All repositories:");
for repo_path in all_repos {
print(` - ${repo_path}`);
}
```
## Error Handling
All methods in the Git module return a Result type, which means they can either succeed or fail with an error. If an error occurs, it will be propagated to the HeroScript script as a runtime error.
For example, if you try to clone a repository that doesn't exist:
```js
// Try to clone a non-existent repository
try {
let git_tree = gittree_new("/root/code");
let repos = git_tree.get("https://github.com/nonexistent/repo.git");
print("This will not be executed if the repository doesn't exist");
} catch(err) {
print(`Error: ${err}`); // Will print the error message from git
}
```
Common errors include:
- Invalid URL
- Repository not found
- Authentication failure
- Network issues
- Local changes exist when trying to pull

View File

@@ -1,10 +0,0 @@
---
title: "intro"
sidebar_position: 1
hide_title: true
---
## HeroScript Script Commands Documentation
The SAL library provides integration with the HeroScript scripting language, allowing you to use powerful system functions within your HeroScript scripts. These functions are organized into modules that provide related functionality.

View File

@@ -1,239 +0,0 @@
---
title: "run containers"
sidebar_position: 21
hide_title: true
---
# Container Manager
The Container Manager module provides a comprehensive API for working with containers using nerdctl. It offers a modern builder pattern approach for container management.
## Container Builder Pattern
The Container Builder Pattern allows for fluent, chainable configuration of containers. This pattern makes container creation more readable and maintainable by allowing you to build complex container configurations step by step.
### Creating a Container
Start by creating a new container instance:
```rhai
// Create an empty container with just a name
let container = nerdctl_container_new("my-container");
// Or create a container from an image
let container = nerdctl_container_from_image("my-container", "nginx:latest");
```
### Configuring the Container
Once you have a container instance, you can configure it using the various builder methods:
```rhai
// Configure the container with various options
let container = nerdctl_container_from_image("web-server", "nginx:latest")
.with_port("8080:80") // Map port 8080 to container port 80
.with_volume("/host/path:/container/path") // Mount a volume
.with_env("NGINX_HOST", "localhost") // Set an environment variable
.with_network("bridge") // Set the network
.with_detach(true); // Run in detached mode
```
### Resetting Container Configuration
If you need to reset the container configuration to its default state while keeping the name and image:
```rhai
// Reset the container configuration
let container = nerdctl_container_from_image("web-server", "nginx:latest")
.reset() // Reset all configuration to defaults
.with_port("8080:80") // Start configuring again
.with_detach(true);
```
### Building and Starting the Container
After configuring the container, you can build and start it:
```rhai
// Build the container (creates it but doesn't start it)
let built_container = container.build();
// Start the container
let start_result = built_container.start();
// Check if the container started successfully
if (start_result.success) {
println("Container started successfully!");
} else {
println(`Failed to start container: ${start_result.stderr}`);
}
```
### Container Lifecycle Operations
Once your container is running, you can perform various operations:
```rhai
// Execute a command in the container
let exec_result = container.exec("ls -la");
// Get container logs
let logs = container.logs();
// Stop the container
let stop_result = container.stop();
// Remove the container
let remove_result = container.remove();
```
## Available Builder Methods
The Container Builder Pattern provides the following methods for configuring containers:
| Method | Description | Example |
| -------------------------------------------------------------------------- | ---------------------------------- | --------------------------------------------------------------------------------- |
| `reset()` | Reset configuration to defaults | `.reset()` |
| `with_port(port)` | Add a port mapping | `.with_port("8080:80")` |
| `with_ports(ports_array)` | Add multiple port mappings | `.with_ports(["8080:80", "443:443"])` |
| `with_volume(volume)` | Add a volume mount | `.with_volume("/host/path:/container/path")` |
| `with_volumes(volumes_array)` | Add multiple volume mounts | `.with_volumes(["/host/path1:/container/path1", "/host/path2:/container/path2"])` |
| `with_env(key, value)` | Add an environment variable | `.with_env("NGINX_HOST", "localhost")` |
| `with_envs(env_map)` | Add multiple environment variables | `.with_envs(#{"KEY1": "value1", "KEY2": "value2"})` |
| `with_network(network)` | Set the network | `.with_network("bridge")` |
| `with_network_alias(alias)` | Add a network alias | `.with_network_alias("web-server")` |
| `with_network_aliases(aliases_array)` | Add multiple network aliases | `.with_network_aliases(["web-server", "http-service"])` |
| `with_cpu_limit(cpus)` | Set CPU limit | `.with_cpu_limit("1.0")` |
| `with_cpu_shares(shares)` | Set CPU shares | `.with_cpu_shares("1024")` |
| `with_memory_limit(memory)` | Set memory limit | `.with_memory_limit("512m")` |
| `with_memory_swap_limit(memory_swap)` | Set memory swap limit | `.with_memory_swap_limit("1g")` |
| `with_restart_policy(policy)` | Set restart policy | `.with_restart_policy("unless-stopped")` |
| `with_health_check(cmd)` | Set health check command | `.with_health_check("curl -f http://localhost/ | | exit 1")` |
| `with_health_check_options(cmd, interval, timeout, retries, start_period)` | Set health check with options | `.with_health_check_options("curl -f http://localhost/ | | exit 1", "5s", "3s", 3, "10s")` |
| `with_snapshotter(snapshotter)` | Set snapshotter | `.with_snapshotter("native")` |
| `with_detach(detach)` | Set detach mode | `.with_detach(true)` |
## Complete Example: Web Server
Here's a complete example that demonstrates setting up an Nginx web server using the Container Builder Pattern:
```rhai
// Create a temporary directory for our files
let work_dir = "/tmp/nerdctl";
mkdir(work_dir);
chdir(work_dir);
// Create a custom index.html file
let html_content = `
<!DOCTYPE html>
<html>
<head>
<title>Rhai Nerdctl Demo</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 40px;
line-height: 1.6;
color: #333;
}
h1 {
color: #0066cc;
}
</style>
</head>
<body>
<h1>Hello from Rhai Nerdctl!</h1>
<p>This page is served by an Nginx container created using the Rhai nerdctl wrapper.</p>
</body>
</html>
`;
// Write the HTML file
let html_file = `${work_dir}/index.html`;
file_write(html_file, html_content);
// Set up environment variables
let env_map = #{};
env_map["NGINX_HOST"] = "localhost";
env_map["NGINX_PORT"] = "80";
env_map["NGINX_WORKER_PROCESSES"] = "auto";
// Create and configure the container
let container_name = "rhai-nginx-demo";
// First, try to remove any existing container with the same name
nerdctl_remove(container_name);
// Create a container with a rich set of options using the builder pattern
let container = nerdctl_container_from_image(container_name, "nginx:latest")
.reset() // Reset to default configuration
.with_detach(true)
.with_ports(["8080:80"]) // Add multiple ports at once
.with_volumes([`${work_dir}:/usr/share/nginx/html`]) // Mount our work dir
.with_envs(env_map) // Add multiple environment variables at once
.with_network("bridge")
.with_network_aliases(["web-server", "nginx-demo"]) // Add multiple network aliases
.with_cpu_limit("1.0")
.with_memory_limit("512m");
// Build and start the container
let built_container = container.build();
let start_result = built_container.start();
println("The web server is running at http://localhost:8080");
```
## Using Local Images Created with Buildah
When working with images created by Buildah, you may need to take additional steps to ensure nerdctl can find and use these images. This is because Buildah and nerdctl may use different storage backends by default.
### Tagging with localhost Prefix
One approach is to tag the Buildah-created image with a `localhost/` prefix:
```rhai
// Create and commit a container with Buildah
let builder = bah_new("my-container", "alpine:latest");
builder.run("echo 'Hello' > /hello.txt");
builder.commit("my-custom-image:latest");
// Tag the image with localhost prefix for nerdctl compatibility
let local_image_name = "localhost/my-custom-image:latest";
bah_image_tag("my-custom-image:latest", local_image_name);
// Now use the image with nerdctl
let container = nerdctl_container_from_image("my-app", local_image_name)
.with_detach(true)
.build();
```
### Using a Local Registry
For more reliable interoperability, you can push the image to a local registry:
```rhai
// Push the Buildah-created image to a local registry
bah_image_push("my-custom-image:latest", "localhost:5000/my-custom-image:latest", false);
// Pull the image with nerdctl
nerdctl_image_pull("localhost:5000/my-custom-image:latest");
// Use the image
let container = nerdctl_container_from_image("my-app", "localhost:5000/my-custom-image:latest")
.with_detach(true)
.build();
```
## Image Management Functions
The module also provides functions for managing container images:
| Function | Description | Example |
| --------------------------------------------- | --------------------------------------- | ------------------------------------------------------------------------------- |
| `nerdctl_images()` | List images in local storage | `nerdctl_images()` |
| `nerdctl_image_remove(image)` | Remove an image | `nerdctl_image_remove("nginx:latest")` |
| `nerdctl_image_push(image, destination)` | Push an image to a registry | `nerdctl_image_push("my-image:latest", "registry.example.com/my-image:latest")` |
| `nerdctl_image_tag(image, new_name)` | Add an additional name to a local image | `nerdctl_image_tag("nginx:latest", "my-nginx:latest")` |
| `nerdctl_image_pull(image)` | Pull an image from a registry | `nerdctl_image_pull("nginx:latest")` |
| `nerdctl_image_commit(container, image_name)` | Commit a container to an image | `nerdctl_image_commit("web-server", "my-nginx:latest")` |
| `nerdctl_image_build(tag, context_path)` | Build an image using a Dockerfile | `nerdctl_image_build("my-image:latest", "./")` |

View File

@@ -1,359 +0,0 @@
---
title: "os"
sidebar_position: 2
hide_title: true
---
# OS Tools
The OS module provides functions for working with files, directories, and downloading files from the internet.
## File System Functions
### `copy(src, dest)`
Recursively copies a file or directory from source to destination.
**Parameters:**
- `src` (string): The source file or directory path
- `dest` (string): The destination path
**Returns:** A message confirming the copy was successful.
**Example:**
```js
// Copy a file
copy("source.txt", "destination.txt");
// Copy a directory recursively
copy("source_dir", "destination_dir");
```
### `exist(path)`
Checks if a file or directory exists.
**Parameters:**
- `path` (string): The path to check
**Returns:** A boolean value - `true` if the file or directory exists, `false` otherwise.
**Example:**
```js
if exist("config.json") {
// File exists, do something
} else {
// File doesn't exist
}
```
### `find_file(dir, filename)`
Finds a file in a directory with support for wildcards.
**Parameters:**
- `dir` (string): The directory to search in
- `filename` (string): The filename pattern to search for (supports wildcards)
**Returns:** The path of the first matching file.
**Example:**
```js
// Find a specific file
let config_file = find_file("./config", "settings.json");
// Find using wildcards
let log_file = find_file("./logs", "*.log");
```
### `find_files(dir, filename)`
Finds multiple files in a directory recursively with support for wildcards.
**Parameters:**
- `dir` (string): The directory to search in
- `filename` (string): The filename pattern to search for (supports wildcards)
**Returns:** A list of matching file paths.
**Example:**
```js
// Find all JSON files
let json_files = find_files("./data", "*.json");
// Process each file
for file in json_files {
print(`Found file: ${file}`);
}
```
### `find_dir(dir, dirname)`
Finds a directory in a parent directory with support for wildcards.
**Parameters:**
- `dir` (string): The parent directory to search in
- `dirname` (string): The directory name pattern to search for (supports wildcards)
**Returns:** The path of the first matching directory.
**Example:**
```js
// Find a specific directory
let config_dir = find_dir("./", "config");
// Find using wildcards
let version_dir = find_dir("./releases", "v*");
```
### `find_dirs(dir, dirname)`
Finds multiple directories in a parent directory recursively with support for wildcards.
**Parameters:**
- `dir` (string): The parent directory to search in
- `dirname` (string): The directory name pattern to search for (supports wildcards)
**Returns:** A list of matching directory paths.
**Example:**
```js
// Find all version directories
let version_dirs = find_dirs("./releases", "v*");
// Process each directory
for dir in version_dirs {
print(`Found directory: ${dir}`);
}
```
### `delete(path)`
Deletes a file or directory. This function is defensive and doesn't error if the file doesn't exist.
**Parameters:**
- `path` (string): The path of the file or directory to delete
**Returns:** A message confirming the deletion was successful.
**Example:**
```js
// Delete a file
delete("temp.txt");
// Delete a directory
delete("temp_dir");
```
### `mv(src, dest)`
Moves a file or directory from source to destination.
**Parameters:**
- `src` (string): The source path
- `dest` (string): The destination path
**Returns:** A message confirming the move was successful.
**Example:**
```js
// Move a file
mv("file.txt", "new_location/file.txt");
// Move a directory
mv("source_dir", "destination_dir");
// Rename a file
mv("old_name.txt", "new_name.txt");
```
### `mkdir(path)`
Creates a directory and all parent directories. This function is defensive and doesn't error if the directory already exists.
**Parameters:**
- `path` (string): The path of the directory to create
**Returns:** A message confirming the directory was created.
**Example:**
```js
// Create a directory
mkdir("new_dir");
// Create nested directories
mkdir("parent/child/grandchild");
```
### `file_size(path)`
Gets the size of a file in bytes.
**Parameters:**
- `path` (string): The path of the file
**Returns:** The size of the file in bytes.
**Example:**
```js
// Get file size
let size = file_size("large_file.dat");
print(`File size: ${size} bytes`);
```
## File Content Functions
### `file_read(path)`
Reads the contents of a file.
**Parameters:**
- `path` (string): The path of the file to read
**Returns:** The content of the file as a string.
**Example:**
```js
// Read a file
let content = file_read("config.json");
print(`File content: ${content}`);
```
### `file_write(path, content)`
Writes content to a file. Creates the file if it doesn't exist, overwrites if it does.
**Parameters:**
- `path` (string): The path of the file to write to
- `content` (string): The content to write to the file
**Returns:** A message confirming the file was written.
**Example:**
```js
// Write to a file
file_write("config.json", "{\n \"setting\": \"value\"\n}");
```
### `file_write_append(path, content)`
Appends content to a file. Creates the file if it doesn't exist.
**Parameters:**
- `path` (string): The path of the file to append to
- `content` (string): The content to append to the file
**Returns:** A message confirming the content was appended.
**Example:**
```js
// Append to a log file
file_write_append("log.txt", "New log entry\n");
```
### `rsync(src, dest)`
Syncs directories using rsync (or platform equivalent).
**Parameters:**
- `src` (string): The source directory
- `dest` (string): The destination directory
**Returns:** A message confirming the directories were synced.
**Example:**
```js
// Sync directories
rsync("source_dir", "backup_dir");
```
### `chdir(path)`
Changes the current working directory.
**Parameters:**
- `path` (string): The path to change to
**Returns:** A message confirming the directory was changed.
**Example:**
```js
// Change directory
chdir("project/src");
```
## Download Functions
### `download(url, dest, min_size_kb)`
Downloads a file from a URL to a destination directory using the curl command. If the URL ends with a supported archive format, the file will be automatically extracted to the destination directory.
**Supported archive formats for automatic extraction:**
- `.tar.gz`
- `.tgz`
- `.tar`
- `.zip`
**Parameters:**
- `url` (string): The URL to download from
- `dest` (string): The destination directory where the file will be saved or extracted
- `min_size_kb` (integer): The minimum expected file size in kilobytes (for validation)
**Returns:** The path where the file was saved or extracted.
**Example:**
```js
// Download a file to a directory
download("https://example.com/file.zip", "downloads/", 10);
```
### `download_file(url, dest, min_size_kb)`
Downloads a file from a URL to a specific file destination using the curl command. This function is designed for downloading files to a specific path, not for extracting archives.
**Parameters:**
- `url` (string): The URL to download from
- `dest` (string): The destination file path where the file will be saved
- `min_size_kb` (integer): The minimum expected file size in kilobytes (for validation)
**Returns:** The path where the file was saved.
**Example:**
```js
// Download a file to a specific path
download_file("https://example.com/file.txt", "downloads/myfile.txt", 10);
```
### `download_install(url, min_size_kb)`
Downloads a file and installs it if it's a supported package format.
**Supported package formats for automatic installation:**
- `.deb` packages on Debian-based systems
**Parameters:**
- `url` (string): The URL to download from
- `min_size_kb` (integer): The minimum expected file size in kilobytes (for validation)
**Returns:** The path where the file was saved or installed.
**Example:**
```js
// Download and install a package
download_install("https://example.com/package.deb", 1000);
```
### `chmod_exec(path)`
Makes a file executable (equivalent to `chmod +x` in Unix).
**Parameters:**
- `path` (string): The path to the file to make executable
**Returns:** A message confirming the file was made executable.
**Example:**
```js
// Make a file executable
chmod_exec("downloads/script.sh");
```

View File

@@ -1,237 +0,0 @@
---
title: "process"
sidebar_position: 3
hide_title: true
---
# Process Module
The Process module provides functions for running commands and managing processes on your system.
## Command Results
### Command Output Information
When you run a command, you get back information about what happened:
- `stdout`: The normal output of the command
- `stderr`: Any error messages from the command
- `success`: Whether the command worked (true) or failed (false)
- `code`: The exit code (0 usually means success)
### Process Information
When you get information about a running process, you can see:
- `pid`: The process ID number
- `name`: The name of the process
- `memory`: How much memory the process is using
- `cpu`: How much CPU the process is using
## Run Functions
### `run(command)`
Runs a command or multiline script with arguments.
**Parameters:**
- `command` (string): The command to run (can be a single command or a multiline script)
**Returns:** The result of the command, including output and whether it succeeded.
**Example 1: Running a simple command**
```js
// Run a simple command
let result = run("ls -la");
// Check if the command was successful
if result.success {
print(`Command output: ${result.stdout}`);
} else {
print(`Command failed with error: ${result.stderr}`);
}
```
**Example 2: Running a multiline script**
```js
// Create a multiline script using backtick string literals
let setup_script = `
# Create directories
mkdir -p /tmp/test_project
cd /tmp/test_project
# Initialize git repository
git init
echo 'Initial content' > README.md
git add README.md
git config --local user.email 'test@example.com'
git config --local user.name 'Test User'
git commit -m 'Initial commit'
`;
// Execute the multiline script
let result = run(setup_script);
```
### `run_silent(command)`
Runs a command or multiline script with arguments silently (without displaying output).
**Parameters:**
- `command` (string): The command to run
**Returns:** The result of the command, without displaying the output.
**Example:**
```js
// Run a command silently
let result = run_silent("git pull");
// Check the exit code
if result.code == 0 {
print("Git pull successful");
} else {
print(`Git pull failed with code ${result.code}`);
}
```
### `new_run_options()`
Creates a new map with default run options.
**Returns:** A map with the following default options:
- `die` (boolean): `true` - Whether to throw an error if the command fails
- `silent` (boolean): `false` - Whether to suppress command output
- `async_exec` (boolean): `false` - Whether to run the command asynchronously
- `log` (boolean): `false` - Whether to log the command execution
**Example:**
```js
// Create run options
let options = new_run_options();
```
### `run_with_options(command, options)`
Runs a command with options specified in a map.
**Parameters:**
- `command` (string): The command to run
- `options` (map): A map of options created with `new_run_options()`
**Returns:** The result of the command with your custom settings applied.
**Example:**
```js
// Create and customize run options
let options = new_run_options();
options.die = false; // Don't throw an error if the command fails
options.silent = true; // Suppress command output
options.async_exec = false; // Run synchronously
options.log = true; // Log the command execution
// Run a command with options
let result = run_with_options("npm install", options);
```
## Working with Multiline Scripts
The Process module allows you to execute multiline scripts, which is particularly useful for complex operations that require multiple commands to be executed in sequence.
### Creating Multiline Scripts
Multiline scripts can be created using backtick (`) string literals in HeroScript:
```js
let my_script = `
# This is a multiline bash script
echo "Hello, World!"
mkdir -p /tmp/my_project
cd /tmp/my_project
touch example.txt
`;
```
## Process Management Functions
### `which(cmd)`
Checks if a command exists in the PATH.
**Parameters:**
- `cmd` (string): The command to check
**Returns:** The full path to the command if found, or nothing if not found.
**Example:**
```js
// Check if a command exists
let git_path = which("git");
if git_path != () {
print(`Git is installed at: ${git_path}`);
} else {
print("Git is not installed");
}
```
### `kill(pattern)`
Kills processes matching a pattern.
**Parameters:**
- `pattern` (string): The pattern to match process names against
**Returns:** A message confirming the processes were killed.
**Example:**
```js
// Kill all processes with "node" in their name
kill("node");
```
### `process_list(pattern)`
Lists processes matching a pattern (or all processes if the pattern is empty).
**Parameters:**
- `pattern` (string): The pattern to match process names against (can be empty to list all processes)
**Returns:** A list of processes matching your search.
**Example:**
```js
// List all processes
let all_processes = process_list("");
// List processes containing "node" in their name
let node_processes = process_list("node");
// Display process information
for process in node_processes {
print(`PID: ${process.pid}, Name: ${process.name}, Memory: ${process.memory}, CPU: ${process.cpu}`);
}
```
### `process_get(pattern)`
Gets a single process matching the pattern. Throws an error if zero or more than one process matches.
**Parameters:**
- `pattern` (string): The pattern to match process names against
**Returns:** Information about the matching process. This will only work if exactly one process matches.
**Example:**
```js
// Try to get a specific process
try {
let process = process_get("my_app");
print(`Found process: PID=${process.pid}, Name=${process.name}`);
} catch(err) {
print(`Error: ${err}`);
}
```

View File

@@ -1,154 +0,0 @@
# RFS (Remote File System)
The RFS module provides a Rust wrapper for the RFS tool, which allows mounting remote filesystems locally and managing filesystem layers.
## Overview
RFS (Remote File System) is a tool that enables mounting various types of remote filesystems locally, as well as creating and managing filesystem layers. The SAL library provides a Rust wrapper for RFS with a fluent builder API, making it easy to use in your applications.
## Features
- Mount remote filesystems locally (SSH, S3, WebDAV, etc.)
- List mounted filesystems
- Unmount filesystems
- Pack directories into filesystem layers
- Unpack filesystem layers
- List contents of filesystem layers
- Verify filesystem layers
## Usage in Rust
### Mounting a Filesystem
```rust
use sal::virt::rfs::{RfsBuilder, MountType};
// Create a new RFS builder
let mount = RfsBuilder::new("user@example.com:/remote/path", "/local/mount/point", MountType::SSH)
.with_option("port", "2222")
.with_option("identity_file", "/path/to/key")
.with_debug(true)
.mount()?;
println!("Mounted filesystem with ID: {}", mount.id);
```
### Listing Mounts
```rust
use sal::virt::rfs::list_mounts;
// List all mounts
let mounts = list_mounts()?;
for mount in mounts {
println!("Mount ID: {}, Source: {}, Target: {}", mount.id, mount.source, mount.target);
}
```
### Unmounting a Filesystem
```rust
use sal::virt::rfs::unmount;
// Unmount a filesystem
unmount("/local/mount/point")?;
```
### Packing a Directory
```rust
use sal::virt::rfs::{PackBuilder, StoreSpec};
// Create store specifications
let store_spec = StoreSpec::new("file")
.with_option("path", "/path/to/store");
// Pack a directory with builder pattern
let result = PackBuilder::new("/path/to/directory", "output.fl")
.with_store_spec(store_spec)
.with_debug(true)
.pack()?;
```
### Unpacking a Filesystem Layer
```rust
use sal::virt::rfs::unpack;
// Unpack a filesystem layer
unpack("input.fl", "/path/to/unpack")?;
```
## Usage in Rhai Scripts
### Mounting a Filesystem
```rhai
// Create a map for mount options
let options = #{
"port": "22",
"identity_file": "/path/to/key",
"readonly": "true"
};
// Mount the directory
let mount = rfs_mount("user@example.com:/remote/path", "/local/mount/point", "ssh", options);
print(`Mounted ${mount.source} to ${mount.target} with ID: ${mount.id}`);
```
### Listing Mounts
```rhai
// List all mounts
let mounts = rfs_list_mounts();
print(`Number of mounts: ${mounts.len()}`);
for mount in mounts {
print(`Mount ID: ${mount.id}, Source: ${mount.source}, Target: ${mount.target}`);
}
```
### Unmounting a Filesystem
```rhai
// Unmount the directory
rfs_unmount("/local/mount/point");
```
### Packing a Directory
```rhai
// Pack the directory
// Store specs format: "file:path=/path/to/store,s3:bucket=my-bucket"
rfs_pack("/path/to/directory", "output.fl", "file:path=/path/to/store");
```
### Unpacking a Filesystem Layer
```rhai
// Unpack the filesystem layer
rfs_unpack("output.fl", "/path/to/unpack");
```
## Mount Types
The RFS module supports various mount types:
- **Local**: Mount a local directory
- **SSH**: Mount a remote directory via SSH
- **S3**: Mount an S3 bucket
- **WebDAV**: Mount a WebDAV server
## Store Specifications
When packing a directory into a filesystem layer, you can specify one or more stores to use. Each store has a type and options:
- **File**: Store files on the local filesystem
- Options: `path` (path to the store)
- **S3**: Store files in an S3 bucket
- Options: `bucket` (bucket name), `region` (AWS region), `access_key`, `secret_key`
## Examples
See the [RFS example script](../../rhaiexamples/rfs_example.rhai) for more examples of how to use the RFS module in Rhai scripts.

View File

@@ -1,237 +0,0 @@
# Text Manipulation Tools
The SAL text module provides powerful text manipulation capabilities that can be used from Rhai scripts. These include text replacement (with regex support), template rendering, string normalization, and text formatting utilities.
## Table of Contents
- [Text Replacement](#text-replacement)
- [Template Rendering](#template-rendering)
- [String Normalization](#string-normalization)
- [Text Formatting](#text-formatting)
## Text Replacement
The text replacement tools allow you to perform simple or complex text replacements, with support for regular expressions, case-insensitive matching, and file operations.
### Basic Usage
```rhai
// Create a new text replacer
let replacer = text_replacer_new()
.pattern("foo") // Set the pattern to search for
.replacement("bar") // Set the replacement text
.build(); // Build the replacer
// Apply the replacer to a string
let result = replacer.replace("foo bar foo");
// Result: "bar bar bar"
```
### Advanced Features
#### Regular Expressions
```rhai
// Create a replacer with regex support
let replacer = text_replacer_new()
.pattern("\\bfoo\\b") // Use regex pattern (word boundary)
.replacement("bar")
.regex(true) // Enable regex mode
.build();
// Apply the replacer to a string
let result = replacer.replace("foo foobar");
// Result: "bar foobar" (only replaces whole "foo" words)
```
#### Case-Insensitive Matching
```rhai
// Create a replacer with case-insensitive matching
let replacer = text_replacer_new()
.pattern("foo")
.replacement("bar")
.regex(true)
.case_insensitive(true) // Enable case-insensitive matching
.build();
// Apply the replacer to a string
let result = replacer.replace("FOO foo Foo");
// Result: "bar bar bar"
```
#### Multiple Replacements
```rhai
// Chain multiple replacements
let replacer = text_replacer_new()
.pattern("foo")
.replacement("bar")
.and() // Add another replacement operation
.pattern("baz")
.replacement("qux")
.build();
// Apply the replacer to a string
let result = replacer.replace("foo baz");
// Result: "bar qux"
```
#### File Operations
```rhai
// Create a replacer
let replacer = text_replacer_new()
.pattern("foo")
.replacement("bar")
.build();
// Replace in a file and get the result as a string
let result = replacer.replace_file("input.txt");
// Replace in a file and write back to the same file
replacer.replace_file_in_place("input.txt");
// Replace in a file and write to a new file
replacer.replace_file_to("input.txt", "output.txt");
```
## Template Rendering
The template rendering tools allow you to create and render templates with variables, using the powerful Tera template engine.
### Basic Usage
```rhai
// Create a template builder with a template file
let template = template_builder_open("template.txt")
.add_var("name", "John") // Add a string variable
.add_var("age", 30) // Add a numeric variable
.add_var("items", ["a", "b", "c"]); // Add an array variable
// Render the template
let result = template.render();
// Render to a file
template.render_to_file("output.txt");
```
### Template Variables
You can add variables of various types:
```rhai
let template = template_builder_open("template.txt")
.add_var("name", "John") // String
.add_var("age", 30) // Integer
.add_var("height", 1.85) // Float
.add_var("is_active", true) // Boolean
.add_var("items", ["a", "b", "c"]); // Array
```
### Using Map for Variables
```rhai
// Create a map of variables
let vars = #{
name: "Alice",
place: "Wonderland"
};
// Add all variables from the map
let template = template_builder_open("template.txt")
.add_vars(vars);
```
### Template Syntax
The template engine uses Tera, which supports:
- Variable interpolation: `{{ variable }}`
- Conditionals: `{% if condition %}...{% endif %}`
- Loops: `{% for item in items %}...{% endfor %}`
- Filters: `{{ variable | filter }}`
Example template:
```
Hello, {{ name }}!
{% if show_greeting %}
Welcome to {{ place }}.
{% endif %}
Your items:
{% for item in items %}
- {{ item }}{% if not loop.last %}{% endif %}
{% endfor %}
```
## String Normalization
The string normalization tools help convert strings to consistent formats for use as file names or paths.
### name_fix
Converts a string to a safe, normalized name by:
- Converting to lowercase
- Replacing spaces and special characters with underscores
- Removing non-alphanumeric characters
```rhai
let fixed_name = name_fix("Hello World!");
// Result: "hello_world"
let fixed_name = name_fix("File-Name.txt");
// Result: "file_name.txt"
```
### path_fix
Similar to name_fix, but preserves path separators:
```rhai
let fixed_path = path_fix("/path/to/Hello World!");
// Result: "/path/to/hello_world"
let fixed_path = path_fix("./relative/path/to/DOCUMENT-123.pdf");
// Result: "./relative/path/to/document_123.pdf"
```
## Text Formatting
Tools to help with text formatting and indentation.
### dedent
Removes common leading whitespace from multi-line strings:
```rhai
let indented_text = " line 1
line 2
line 3";
let dedented = dedent(indented_text);
// Result: "line 1
// line 2
// line 3"
```
### prefix
Adds a prefix to every line in a multi-line string:
```rhai
let text = "line 1
line 2
line 3";
let prefixed = prefix(text, " ");
// Result: " line 1
// line 2
// line 3"
```
## Examples
See the [text_tools.rhai](https://github.com/ourworld-tf/herocode/blob/main/sal/src/rhaiexamples/text_tools.rhai) example script for more detailed examples of using these text manipulation tools.

View File

@@ -1,172 +0,0 @@
// 01_builder_pattern.rhai
// Tests for Buildah Builder pattern
// Custom assert function
fn assert_true(condition, message) {
if !condition {
print(`ASSERTION FAILED: ${message}`);
throw message;
}
}
// Custom assert_eq function
fn assert_eq(actual, expected, message) {
if actual != expected {
print(`ASSERTION FAILED: ${message}`);
print(`Expected: "${expected}"`);
print(`Actual: "${actual}"`);
throw message;
}
}
// Helper function to check if buildah is available
fn is_buildah_available() {
try {
let result = run("which buildah");
return result.success;
} catch(err) {
return false;
}
}
print("=== Testing Buildah Builder Pattern ===");
// Check if buildah is available
let buildah_available = is_buildah_available();
if !buildah_available {
print("Buildah is not available. Skipping Buildah tests.");
// Exit gracefully without error
return;
}
print("✓ Buildah is available");
// Test creating a new Builder
print("Testing bah_new()...");
try {
let builder = bah_new("rhai_test_container", "alpine:latest");
// Test Builder properties
print("Testing Builder properties...");
assert_true(builder.container_id != "", "Container ID should not be empty");
assert_eq(builder.name, "rhai_test_container", "Container name should match");
assert_eq(builder.image, "alpine:latest", "Image name should match");
// Test debug mode
print("Testing debug mode...");
assert_true(!builder.debug_mode, "Debug mode should be off by default");
builder.debug_mode = true;
assert_true(builder.debug_mode, "Debug mode should be on after setting");
// Test running a command
print("Testing run()...");
let result = builder.run("echo 'Hello from container'");
assert_true(result.success, "Command should succeed");
assert_true(result.stdout.contains("Hello from container"), "Command output should contain expected text");
print("✓ run(): Command executed successfully");
// Test writing content to a file in the container
print("Testing write_content()...");
let content = "Hello from a file";
builder.write_content(content, "/test_file.txt");
// Verify the content was written
let read_result = builder.run("cat /test_file.txt");
assert_true(read_result.success, "Command should succeed");
assert_true(read_result.stdout.contains(content), "File content should match what was written");
print("✓ write_content(): Content written successfully");
// Test reading content from a file in the container
print("Testing read_content()...");
let read_content = builder.read_content("/test_file.txt");
assert_true(read_content.contains(content), "Read content should match what was written");
print("✓ read_content(): Content read successfully");
// Test setting entrypoint
print("Testing set_entrypoint()...");
let entrypoint = ["/bin/sh", "-c"];
builder.set_entrypoint(entrypoint);
print("✓ set_entrypoint(): Entrypoint set successfully");
// Test setting cmd
print("Testing set_cmd()...");
let cmd = ["echo", "Hello from CMD"];
builder.set_cmd(cmd);
print("✓ set_cmd(): CMD set successfully");
// Test adding a file
print("Testing add()...");
// Create a test file
file_write("test_add_file.txt", "Test content for add");
builder.add("test_add_file.txt", "/");
// Verify the file was added
let add_result = builder.run("cat /test_add_file.txt");
assert_true(add_result.success, "Command should succeed");
assert_true(add_result.stdout.contains("Test content for add"), "Added file content should match");
print("✓ add(): File added successfully");
// Test copying a file
print("Testing copy()...");
// Create a test file
file_write("test_copy_file.txt", "Test content for copy");
builder.copy("test_copy_file.txt", "/");
// Verify the file was copied
let copy_result = builder.run("cat /test_copy_file.txt");
assert_true(copy_result.success, "Command should succeed");
assert_true(copy_result.stdout.contains("Test content for copy"), "Copied file content should match");
print("✓ copy(): File copied successfully");
// Test committing to an image
print("Testing commit()...");
let image_name = "rhai_test_image:latest";
builder.commit(image_name);
print("✓ commit(): Container committed to image successfully");
// Test removing the container
print("Testing remove()...");
builder.remove();
print("✓ remove(): Container removed successfully");
// Clean up test files
delete("test_add_file.txt");
delete("test_copy_file.txt");
// Test image operations
print("Testing image operations...");
// Test listing images
print("Testing images()...");
let images = builder.images();
assert_true(images.len() > 0, "There should be at least one image");
print("✓ images(): Images listed successfully");
// Test removing the image
print("Testing image_remove()...");
builder.image_remove(image_name);
print("✓ image_remove(): Image removed successfully");
print("All Builder pattern tests completed successfully!");
} catch(err) {
print(`Error: ${err}`);
// Clean up in case of error
try {
// Remove test container if it exists
run("buildah rm rhai_test_container");
} catch(_) {}
try {
// Remove test image if it exists
run("buildah rmi rhai_test_image:latest");
} catch(_) {}
try {
// Remove test files if they exist
delete("test_add_file.txt");
delete("test_copy_file.txt");
} catch(_) {}
throw err;
}

View File

@@ -1,150 +0,0 @@
// 02_image_operations.rhai
// Tests for Buildah image operations
// Custom assert function
fn assert_true(condition, message) {
if !condition {
print(`ASSERTION FAILED: ${message}`);
throw message;
}
}
// Custom assert_eq function
fn assert_eq(actual, expected, message) {
if actual != expected {
print(`ASSERTION FAILED: ${message}`);
print(`Expected: "${expected}"`);
print(`Actual: "${actual}"`);
throw message;
}
}
// Helper function to check if buildah is available
fn is_buildah_available() {
try {
let result = run("which buildah");
return result.success;
} catch(err) {
return false;
}
}
// Helper function to check if an image exists
fn image_exists(image_name) {
try {
let result = run(`buildah images -q ${image_name}`);
return result.success && result.stdout.trim() != "";
} catch(err) {
return false;
}
}
print("=== Testing Buildah Image Operations ===");
// Check if buildah is available
let buildah_available = is_buildah_available();
if !buildah_available {
print("Buildah is not available. Skipping Buildah tests.");
// Exit gracefully without error
return;
}
print("✓ Buildah is available");
// Create a temporary directory for testing
let test_dir = "rhai_test_buildah";
mkdir(test_dir);
try {
// Create a builder for testing
let builder = bah_new("rhai_test_container", "alpine:latest");
// Enable debug mode
builder.debug_mode = true;
// Test image_pull
print("Testing image_pull()...");
// Use a small image for testing
let pull_result = builder.image_pull("alpine:3.14", true);
assert_true(pull_result.success, "Image pull should succeed");
print("✓ image_pull(): Image pulled successfully");
// Test image_tag
print("Testing image_tag()...");
let tag_result = builder.image_tag("alpine:3.14", "rhai_test_tag:latest");
assert_true(tag_result.success, "Image tag should succeed");
print("✓ image_tag(): Image tagged successfully");
// Test images (list)
print("Testing images()...");
let images = builder.images();
assert_true(images.len() > 0, "There should be at least one image");
// Find our tagged image
let found_tag = false;
for image in images {
if image.names.contains("rhai_test_tag:latest") {
found_tag = true;
break;
}
}
assert_true(found_tag, "Tagged image should be in the list");
print("✓ images(): Images listed successfully");
// Test build
print("Testing build()...");
// Create a simple Dockerfile
let dockerfile_content = `FROM alpine:latest
RUN echo "Hello from Dockerfile" > /hello.txt
CMD ["cat", "/hello.txt"]
`;
file_write(`${test_dir}/Dockerfile`, dockerfile_content);
// Build the image
let build_result = builder.build("rhai_test_build:latest", test_dir, "Dockerfile", "oci");
assert_true(build_result.success, "Image build should succeed");
print("✓ build(): Image built successfully");
// Verify the built image exists
assert_true(image_exists("rhai_test_build:latest"), "Built image should exist");
// Test image_remove
print("Testing image_remove()...");
// Remove the tagged image
let remove_tag_result = builder.image_remove("rhai_test_tag:latest");
assert_true(remove_tag_result.success, "Image removal should succeed");
print("✓ image_remove(): Tagged image removed successfully");
// Remove the built image
let remove_build_result = builder.image_remove("rhai_test_build:latest");
assert_true(remove_build_result.success, "Image removal should succeed");
print("✓ image_remove(): Built image removed successfully");
// Clean up
builder.remove();
print("✓ Cleanup: Container removed");
print("All image operations tests completed successfully!");
} catch(err) {
print(`Error: ${err}`);
// Clean up in case of error
try {
// Remove test container if it exists
run("buildah rm rhai_test_container");
} catch(_) {}
try {
// Remove test images if they exist
run("buildah rmi rhai_test_tag:latest");
run("buildah rmi rhai_test_build:latest");
} catch(_) {}
throw err;
} finally {
// Clean up test directory
delete(test_dir);
print("✓ Cleanup: Test directory removed");
}

View File

@@ -1,127 +0,0 @@
// 03_container_operations.rhai
// Tests for Buildah container operations
// Custom assert function
fn assert_true(condition, message) {
if !condition {
print(`ASSERTION FAILED: ${message}`);
throw message;
}
}
// Custom assert_eq function
fn assert_eq(actual, expected, message) {
if actual != expected {
print(`ASSERTION FAILED: ${message}`);
print(`Expected: "${expected}"`);
print(`Actual: "${actual}"`);
throw message;
}
}
// Helper function to check if buildah is available
fn is_buildah_available() {
try {
let result = run("which buildah");
return result.success;
} catch(err) {
return false;
}
}
print("=== Testing Buildah Container Operations ===");
// Check if buildah is available
let buildah_available = is_buildah_available();
if !buildah_available {
print("Buildah is not available. Skipping Buildah tests.");
// Exit gracefully without error
return;
}
print("✓ Buildah is available");
try {
// Test creating a new Builder
print("Testing bah_new() and reset()...");
let builder = bah_new("rhai_test_container", "alpine:latest");
// Enable debug mode
builder.debug_mode = true;
// Test reset
print("Testing reset()...");
builder.reset();
print("✓ reset(): Container reset successfully");
// Create a new container
builder = bah_new("rhai_test_container", "alpine:latest");
// Test config
print("Testing config()...");
let config_options = #{
"LABEL": "rhai_test=true",
"ENV": "TEST_VAR=test_value"
};
builder.config(config_options);
print("✓ config(): Container configured successfully");
// Test run with isolation
print("Testing run_with_isolation()...");
let isolation_result = builder.run_with_isolation("echo 'Hello with isolation'", "oci");
assert_true(isolation_result.success, "Command with isolation should succeed");
assert_true(isolation_result.stdout.contains("Hello with isolation"), "Command output should contain expected text");
print("✓ run_with_isolation(): Command executed successfully");
// Test content operations
print("Testing content operations...");
// Write content to a file
let script_content = `#!/bin/sh
echo "Hello from script"
`;
builder.write_content(script_content, "/script.sh");
// Make the script executable
builder.run("chmod +x /script.sh");
// Run the script
let script_result = builder.run("/script.sh");
assert_true(script_result.success, "Script should execute successfully");
assert_true(script_result.stdout.contains("Hello from script"), "Script output should contain expected text");
print("✓ Content operations: Script created and executed successfully");
// Test commit with config
print("Testing commit with config...");
let commit_options = #{
"author": "Rhai Test",
"message": "Test commit"
};
builder.commit("rhai_test_commit:latest", commit_options);
print("✓ commit(): Container committed with config successfully");
// Clean up
builder.remove();
print("✓ Cleanup: Container removed");
// Remove the committed image
builder.image_remove("rhai_test_commit:latest");
print("✓ Cleanup: Committed image removed");
print("All container operations tests completed successfully!");
} catch(err) {
print(`Error: ${err}`);
// Clean up in case of error
try {
// Remove test container if it exists
run("buildah rm rhai_test_container");
} catch(_) {}
try {
// Remove test image if it exists
run("buildah rmi rhai_test_commit:latest");
} catch(_) {}
throw err;
}

View File

@@ -1,155 +0,0 @@
// run_all_tests.rhai
// Runs all Buildah module tests
print("=== Running Buildah Module Tests ===");
// Custom assert function
fn assert_true(condition, message) {
if !condition {
print(`ASSERTION FAILED: ${message}`);
throw message;
}
}
// Helper function to check if buildah is available
fn is_buildah_available() {
try {
let result = run("which buildah");
return result.success;
} catch(e) {
return false;
}
}
// Run each test directly
let passed = 0;
let failed = 0;
let skipped = 0;
let total = 0;
// Check if buildah is available
let buildah_available = is_buildah_available();
if !buildah_available {
print("Buildah is not available. Skipping all Buildah tests.");
skipped = 3; // Skip all three tests
total = 3;
} else {
// Test 1: Builder Pattern
print("\n--- Running Builder Pattern Tests ---");
try {
// Create a builder
let builder = bah_new("rhai_test_container", "alpine:latest");
// Test basic properties
assert_true(builder.container_id != "", "Container ID should not be empty");
assert_true(builder.name == "rhai_test_container", "Container name should match");
// Run a simple command
let result = builder.run("echo 'Hello from container'");
assert_true(result.success, "Command should succeed");
// Clean up
builder.remove();
print("--- Builder Pattern Tests completed successfully ---");
passed += 1;
} catch(err) {
print(`!!! Error in Builder Pattern Tests: ${err}`);
failed += 1;
// Clean up in case of error
try {
run("buildah rm rhai_test_container");
} catch(e) {
// Ignore errors during cleanup
}
}
total += 1;
// Test 2: Image Operations
print("\n--- Running Image Operations Tests ---");
try {
// Create a temporary directory for testing
let test_dir = "rhai_test_buildah";
mkdir(test_dir);
// Create a builder
let builder = bah_new("rhai_test_container", "alpine:latest");
// List images
let images = builder.images();
assert_true(images.len() > 0, "There should be at least one image");
// Clean up
builder.remove();
delete(test_dir);
print("--- Image Operations Tests completed successfully ---");
passed += 1;
} catch(err) {
print(`!!! Error in Image Operations Tests: ${err}`);
failed += 1;
// Clean up in case of error
try {
run("buildah rm rhai_test_container");
delete("rhai_test_buildah");
} catch(e) {
// Ignore errors during cleanup
}
}
total += 1;
// Test 3: Container Operations
print("\n--- Running Container Operations Tests ---");
try {
// Create a builder
let builder = bah_new("rhai_test_container", "alpine:latest");
// Test reset
builder.reset();
// Create a new container
builder = bah_new("rhai_test_container", "alpine:latest");
// Run a command
let result = builder.run("echo 'Hello from container'");
assert_true(result.success, "Command should succeed");
// Clean up
builder.remove();
print("--- Container Operations Tests completed successfully ---");
passed += 1;
} catch(err) {
print(`!!! Error in Container Operations Tests: ${err}`);
failed += 1;
// Clean up in case of error
try {
run("buildah rm rhai_test_container");
} catch(e) {
// Ignore errors during cleanup
}
}
total += 1;
}
print("\n=== Test Summary ===");
print(`Passed: ${passed}`);
print(`Failed: ${failed}`);
print(`Skipped: ${skipped}`);
print(`Total: ${total}`);
if failed == 0 {
if skipped > 0 {
print("\n⚠ All tests skipped or passed!");
} else {
print("\n✅ All tests passed!");
}
} else {
print("\n❌ Some tests failed!");
}
// Return the number of failed tests (0 means success)
failed;

View File

@@ -1,76 +0,0 @@
// 01_git_basic.rhai
// Tests for basic Git operations in the Git module
// Custom assert function
fn assert_true(condition, message) {
if !condition {
print(`ASSERTION FAILED: ${message}`);
throw message;
}
}
// Create a temporary directory for Git operations
let test_dir = "rhai_test_git";
mkdir(test_dir);
print(`Created test directory: ${test_dir}`);
// Test GitTree constructor
print("Testing GitTree constructor...");
let git_tree = git_tree_new(test_dir);
print("✓ GitTree created successfully");
// Test GitTree.list() with empty directory
print("Testing GitTree.list() with empty directory...");
let repos = git_tree.list();
assert_true(repos.len() == 0, "Expected empty list of repositories");
print(`✓ GitTree.list(): Found ${repos.len()} repositories (expected 0)`);
// Test GitTree.find() with empty directory
print("Testing GitTree.find() with empty directory...");
let found_repos = git_tree.find("*");
assert_true(found_repos.len() == 0, "Expected empty list of repositories");
print(`✓ GitTree.find(): Found ${found_repos.len()} repositories (expected 0)`);
// Test GitTree.get() with a URL to clone a repository
// We'll use a small, public repository for testing
print("Testing GitTree.get() with URL...");
let repo_url = "https://github.com/rhaiscript/playground.git";
let repo = git_tree.get(repo_url);
print(`✓ GitTree.get(): Repository cloned successfully to ${repo.path()}`);
// Test GitRepo.path()
print("Testing GitRepo.path()...");
let repo_path = repo.path();
assert_true(repo_path.contains(test_dir), "Repository path should contain test directory");
print(`✓ GitRepo.path(): ${repo_path}`);
// Test GitRepo.has_changes()
print("Testing GitRepo.has_changes()...");
let has_changes = repo.has_changes();
print(`✓ GitRepo.has_changes(): ${has_changes}`);
// Test GitTree.list() after cloning
print("Testing GitTree.list() after cloning...");
let repos_after_clone = git_tree.list();
assert_true(repos_after_clone.len() > 0, "Expected non-empty list of repositories");
print(`✓ GitTree.list(): Found ${repos_after_clone.len()} repositories`);
// Test GitTree.find() after cloning
print("Testing GitTree.find() after cloning...");
let found_repos_after_clone = git_tree.find("*");
assert_true(found_repos_after_clone.len() > 0, "Expected non-empty list of repositories");
print(`✓ GitTree.find(): Found ${found_repos_after_clone.len()} repositories`);
// Test GitTree.get() with a path to an existing repository
print("Testing GitTree.get() with path...");
let repo_name = repos_after_clone[0];
let repo_by_path = git_tree.get(repo_name);
print(`✓ GitTree.get(): Repository opened successfully from ${repo_by_path.path()}`);
// Clean up
print("Cleaning up...");
delete(test_dir);
assert_true(!exist(test_dir), "Directory deletion failed");
print(`✓ Cleanup: Directory ${test_dir} removed`);
print("All basic Git tests completed successfully!");

View File

@@ -1,63 +0,0 @@
// 02_git_operations.rhai
// Tests for Git operations like pull, reset, commit, and push
// Custom assert function
fn assert_true(condition, message) {
if !condition {
print(`ASSERTION FAILED: ${message}`);
throw message;
}
}
// Create a temporary directory for Git operations
let test_dir = "rhai_test_git_ops";
mkdir(test_dir);
print(`Created test directory: ${test_dir}`);
// Create a GitTree
print("Creating GitTree...");
let git_tree = git_tree_new(test_dir);
print("✓ GitTree created successfully");
// Clone a repository
print("Cloning repository...");
let repo_url = "https://github.com/rhaiscript/playground.git";
let repo = git_tree.get(repo_url);
print(`✓ Repository cloned successfully to ${repo.path()}`);
// Test GitRepo.pull()
print("Testing GitRepo.pull()...");
try {
let pull_result = repo.pull();
print("✓ GitRepo.pull(): Pull successful");
} catch(err) {
// Pull might fail if there are local changes or network issues
// This is expected in some cases, so we'll just log it
print(`Note: Pull failed with error: ${err}`);
print("✓ GitRepo.pull(): Error handled gracefully");
}
// Test GitRepo.reset()
print("Testing GitRepo.reset()...");
try {
let reset_result = repo.reset();
print("✓ GitRepo.reset(): Reset successful");
} catch(err) {
// Reset might fail in some cases
print(`Note: Reset failed with error: ${err}`);
print("✓ GitRepo.reset(): Error handled gracefully");
}
// Note: We won't test commit and push as they would modify the remote repository
// Instead, we'll just verify that the methods exist and can be called
print("Note: Not testing commit and push to avoid modifying remote repositories");
print("✓ GitRepo.commit() and GitRepo.push() methods exist");
// Clean up
print("Cleaning up...");
delete(test_dir);
assert_true(!exist(test_dir), "Directory deletion failed");
print(`✓ Cleanup: Directory ${test_dir} removed`);
print("All Git operations tests completed successfully!");

View File

@@ -1,94 +0,0 @@
// run_all_tests.rhai
// Runs all Git module tests
print("=== Running Git Module Tests ===");
// Custom assert function
fn assert_true(condition, message) {
if !condition {
print(`ASSERTION FAILED: ${message}`);
throw message;
}
}
// Run each test directly
let passed = 0;
let failed = 0;
// Test 1: Basic Git Operations
print("\n--- Running Basic Git Operations Tests ---");
try {
// Create a temporary directory for Git operations
let test_dir = "rhai_test_git";
mkdir(test_dir);
print(`Created test directory: ${test_dir}`);
// Test GitTree constructor
print("Testing GitTree constructor...");
let git_tree = git_tree_new(test_dir);
print("✓ GitTree created successfully");
// Test GitTree.list() with empty directory
print("Testing GitTree.list() with empty directory...");
let repos = git_tree.list();
assert_true(repos.len() == 0, "Expected empty list of repositories");
print(`✓ GitTree.list(): Found ${repos.len()} repositories (expected 0)`);
// Test GitTree.find() with empty directory
print("Testing GitTree.find() with empty directory...");
let found_repos = git_tree.find("*");
assert_true(found_repos.len() == 0, "Expected empty list of repositories");
print(`✓ GitTree.find(): Found ${found_repos.len()} repositories (expected 0)`);
// Clean up
print("Cleaning up...");
delete(test_dir);
assert_true(!exist(test_dir), "Directory deletion failed");
print(`✓ Cleanup: Directory ${test_dir} removed`);
print("--- Basic Git Operations Tests completed successfully ---");
passed += 1;
} catch(err) {
print(`!!! Error in Basic Git Operations Tests: ${err}`);
failed += 1;
}
// Test 2: Git Repository Operations
print("\n--- Running Git Repository Operations Tests ---");
try {
// Create a temporary directory for Git operations
let test_dir = "rhai_test_git_ops";
mkdir(test_dir);
print(`Created test directory: ${test_dir}`);
// Create a GitTree
print("Creating GitTree...");
let git_tree = git_tree_new(test_dir);
print("✓ GitTree created successfully");
// Clean up
print("Cleaning up...");
delete(test_dir);
assert_true(!exist(test_dir), "Directory deletion failed");
print(`✓ Cleanup: Directory ${test_dir} removed`);
print("--- Git Repository Operations Tests completed successfully ---");
passed += 1;
} catch(err) {
print(`!!! Error in Git Repository Operations Tests: ${err}`);
failed += 1;
}
print("\n=== Test Summary ===");
print(`Passed: ${passed}`);
print(`Failed: ${failed}`);
print(`Total: ${passed + failed}`);
if failed == 0 {
print("\n✅ All tests passed!");
} else {
print("\n❌ Some tests failed!");
}
// Return the number of failed tests (0 means success)
failed;

View File

@@ -1,176 +0,0 @@
// 01_container_operations.rhai
// Tests for Nerdctl container operations
// Custom assert function
fn assert_true(condition, message) {
if !condition {
print(`ASSERTION FAILED: ${message}`);
throw message;
}
}
// Custom assert_eq function
fn assert_eq(actual, expected, message) {
if actual != expected {
print(`ASSERTION FAILED: ${message}`);
print(`Expected: "${expected}"`);
print(`Actual: "${actual}"`);
throw message;
}
}
// Helper function to check if nerdctl is available
fn is_nerdctl_available() {
try {
let result = run("which nerdctl");
return result.success;
} catch(err) {
return false;
}
}
// Helper function to check if a container exists
fn container_exists(container_name) {
try {
let result = run(`nerdctl ps -a --format "{{.Names}}" | grep -w ${container_name}`);
return result.success;
} catch(err) {
return false;
}
}
// Helper function to clean up a container if it exists
fn cleanup_container(container_name) {
if container_exists(container_name) {
try {
run(`nerdctl stop ${container_name}`);
run(`nerdctl rm ${container_name}`);
print(`Cleaned up container: ${container_name}`);
} catch(err) {
print(`Error cleaning up container ${container_name}: ${err}`);
}
}
}
print("=== Testing Nerdctl Container Operations ===");
// Check if nerdctl is available
let nerdctl_available = is_nerdctl_available();
if !nerdctl_available {
print("nerdctl is not available. Skipping Nerdctl tests.");
// Exit gracefully without error
return;
}
print("✓ nerdctl is available");
// Define test container name
let container_name = "rhai_test_container";
// Clean up any existing test container
cleanup_container(container_name);
try {
// Test creating a new Container
print("Testing nerdctl_container_new()...");
let container = nerdctl_container_new(container_name);
// Test Container properties
print("Testing Container properties...");
assert_eq(container.name, container_name, "Container name should match");
assert_eq(container.container_id, "", "Container ID should be empty initially");
// Test setting container image
print("Testing with_image()...");
container.with_image("alpine:latest");
assert_eq(container.image, "alpine:latest", "Container image should match");
// Test setting detach mode
print("Testing with_detach()...");
container.with_detach(true);
assert_true(container.detach, "Container detach mode should be true");
// Test setting environment variables
print("Testing with_env()...");
container.with_env("TEST_VAR", "test_value");
// Test setting multiple environment variables
print("Testing with_envs()...");
let env_map = #{
"VAR1": "value1",
"VAR2": "value2"
};
container.with_envs(env_map);
// Test setting ports
print("Testing with_port()...");
container.with_port("8080:80");
// Test setting multiple ports
print("Testing with_ports()...");
container.with_ports(["9090:90", "7070:70"]);
// Test setting volumes
print("Testing with_volume()...");
// Create a test directory for volume mounting
let test_dir = "rhai_test_nerdctl_volume";
mkdir(test_dir);
container.with_volume(`${test_dir}:/data`);
// Test setting resource limits
print("Testing with_cpu_limit() and with_memory_limit()...");
container.with_cpu_limit("0.5");
container.with_memory_limit("256m");
// Test running the container
print("Testing run()...");
let run_result = container.run();
assert_true(run_result.success, "Container run should succeed");
assert_true(container.container_id != "", "Container ID should not be empty after run");
print(`✓ run(): Container started with ID: ${container.container_id}`);
// Test executing a command in the container
print("Testing exec()...");
let exec_result = container.exec("echo 'Hello from container'");
assert_true(exec_result.success, "Container exec should succeed");
assert_true(exec_result.stdout.contains("Hello from container"), "Exec output should contain expected text");
print("✓ exec(): Command executed successfully");
// Test getting container logs
print("Testing logs()...");
let logs_result = container.logs();
assert_true(logs_result.success, "Container logs should succeed");
print("✓ logs(): Logs retrieved successfully");
// Test stopping the container
print("Testing stop()...");
let stop_result = container.stop();
assert_true(stop_result.success, "Container stop should succeed");
print("✓ stop(): Container stopped successfully");
// Test removing the container
print("Testing remove()...");
let remove_result = container.remove();
assert_true(remove_result.success, "Container remove should succeed");
print("✓ remove(): Container removed successfully");
// Clean up test directory
delete(test_dir);
print("✓ Cleanup: Test directory removed");
print("All container operations tests completed successfully!");
} catch(err) {
print(`Error: ${err}`);
// Clean up in case of error
cleanup_container(container_name);
// Clean up test directory
try {
delete("rhai_test_nerdctl_volume");
} catch(e) {
// Ignore errors during cleanup
}
throw err;
}

View File

@@ -1,168 +0,0 @@
// 02_image_operations.rhai
// Tests for Nerdctl image operations
// Custom assert function
fn assert_true(condition, message) {
if !condition {
print(`ASSERTION FAILED: ${message}`);
throw message;
}
}
// Custom assert_eq function
fn assert_eq(actual, expected, message) {
if actual != expected {
print(`ASSERTION FAILED: ${message}`);
print(`Expected: "${expected}"`);
print(`Actual: "${actual}"`);
throw message;
}
}
// Helper function to check if nerdctl is available
fn is_nerdctl_available() {
try {
let result = run("which nerdctl");
return result.success;
} catch(err) {
return false;
}
}
// Helper function to check if an image exists
fn image_exists(image_name) {
try {
let result = run(`nerdctl images -q ${image_name}`);
return result.success && result.stdout.trim() != "";
} catch(err) {
return false;
}
}
// Helper function to clean up an image if it exists
fn cleanup_image(image_name) {
if image_exists(image_name) {
try {
run(`nerdctl rmi ${image_name}`);
print(`Cleaned up image: ${image_name}`);
} catch(err) {
print(`Error cleaning up image ${image_name}: ${err}`);
}
}
}
print("=== Testing Nerdctl Image Operations ===");
// Check if nerdctl is available
let nerdctl_available = is_nerdctl_available();
if !nerdctl_available {
print("nerdctl is not available. Skipping Nerdctl tests.");
// Exit gracefully without error
return;
}
print("✓ nerdctl is available");
// Create a temporary directory for testing
let test_dir = "rhai_test_nerdctl";
mkdir(test_dir);
try {
// Test pulling an image
print("Testing nerdctl_image_pull()...");
// Use a small image for testing
let pull_result = nerdctl_image_pull("alpine:latest");
assert_true(pull_result.success, "Image pull should succeed");
print("✓ nerdctl_image_pull(): Image pulled successfully");
// Test listing images
print("Testing nerdctl_images()...");
let images_result = nerdctl_images();
assert_true(images_result.success, "Image listing should succeed");
assert_true(images_result.stdout.contains("alpine"), "Image list should contain alpine");
print("✓ nerdctl_images(): Images listed successfully");
// Test tagging an image
print("Testing nerdctl_image_tag()...");
let tag_result = nerdctl_image_tag("alpine:latest", "rhai_test_image:latest");
assert_true(tag_result.success, "Image tag should succeed");
print("✓ nerdctl_image_tag(): Image tagged successfully");
// Test building an image
print("Testing nerdctl_image_build()...");
// Create a simple Dockerfile
let dockerfile_content = `FROM alpine:latest
RUN echo "Hello from Dockerfile" > /hello.txt
CMD ["cat", "/hello.txt"]
`;
file_write(`${test_dir}/Dockerfile`, dockerfile_content);
// Build the image
let build_result = nerdctl_image_build("rhai_test_build:latest", test_dir);
assert_true(build_result.success, "Image build should succeed");
print("✓ nerdctl_image_build(): Image built successfully");
// Test running a container from the built image
print("Testing container from built image...");
let container_name = "rhai_test_container_from_build";
// Clean up any existing container with the same name
try {
run(`nerdctl stop ${container_name}`);
run(`nerdctl rm ${container_name}`);
} catch(e) {
// Ignore errors during cleanup
}
// Run the container
let run_result = nerdctl_run_with_name("rhai_test_build:latest", container_name);
assert_true(run_result.success, "Container run should succeed");
assert_true(run_result.stdout.contains("Hello from Dockerfile"), "Container output should contain expected text");
print("✓ Container from built image ran successfully");
// Clean up the container
let stop_result = nerdctl_stop(container_name);
assert_true(stop_result.success, "Container stop should succeed");
let remove_result = nerdctl_remove(container_name);
assert_true(remove_result.success, "Container remove should succeed");
print("✓ Cleanup: Container removed");
// Test removing images
print("Testing nerdctl_image_remove()...");
// Remove the tagged image
let remove_tag_result = nerdctl_image_remove("rhai_test_image:latest");
assert_true(remove_tag_result.success, "Image removal should succeed");
print("✓ nerdctl_image_remove(): Tagged image removed successfully");
// Remove the built image
let remove_build_result = nerdctl_image_remove("rhai_test_build:latest");
assert_true(remove_build_result.success, "Image removal should succeed");
print("✓ nerdctl_image_remove(): Built image removed successfully");
print("All image operations tests completed successfully!");
} catch(err) {
print(`Error: ${err}`);
// Clean up in case of error
try {
run("nerdctl stop rhai_test_container_from_build");
run("nerdctl rm rhai_test_container_from_build");
} catch(e) {
// Ignore errors during cleanup
}
try {
cleanup_image("rhai_test_image:latest");
cleanup_image("rhai_test_build:latest");
} catch(e) {
// Ignore errors during cleanup
}
throw err;
} finally {
// Clean up test directory
delete(test_dir);
print("✓ Cleanup: Test directory removed");
}

View File

@@ -1,166 +0,0 @@
// 03_container_builder.rhai
// Tests for Nerdctl Container Builder pattern
// Custom assert function
fn assert_true(condition, message) {
if !condition {
print(`ASSERTION FAILED: ${message}`);
throw message;
}
}
// Custom assert_eq function
fn assert_eq(actual, expected, message) {
if actual != expected {
print(`ASSERTION FAILED: ${message}`);
print(`Expected: "${expected}"`);
print(`Actual: "${actual}"`);
throw message;
}
}
// Helper function to check if nerdctl is available
fn is_nerdctl_available() {
try {
let result = run("which nerdctl");
return result.success;
} catch(err) {
return false;
}
}
// Helper function to check if a container exists
fn container_exists(container_name) {
try {
let result = run(`nerdctl ps -a --format "{{.Names}}" | grep -w ${container_name}`);
return result.success;
} catch(err) {
return false;
}
}
// Helper function to clean up a container if it exists
fn cleanup_container(container_name) {
if container_exists(container_name) {
try {
run(`nerdctl stop ${container_name}`);
run(`nerdctl rm ${container_name}`);
print(`Cleaned up container: ${container_name}`);
} catch(err) {
print(`Error cleaning up container ${container_name}: ${err}`);
}
}
}
print("=== Testing Nerdctl Container Builder Pattern ===");
// Check if nerdctl is available
let nerdctl_available = is_nerdctl_available();
if !nerdctl_available {
print("nerdctl is not available. Skipping Nerdctl tests.");
// Exit gracefully without error
return;
}
print("✓ nerdctl is available");
// Define test container name
let container_name = "rhai_test_builder";
// Clean up any existing test container
cleanup_container(container_name);
// Create test directories
let work_dir = "rhai_test_nerdctl_work";
let config_dir = "rhai_test_nerdctl_config";
mkdir(work_dir);
mkdir(config_dir);
try {
// Test creating a container from an image with builder pattern
print("Testing nerdctl_container_from_image() with builder pattern...");
// Create a container with a rich set of options using the builder pattern
let container = nerdctl_container_from_image(container_name, "alpine:latest")
.reset() // Reset to default configuration
.with_detach(true)
.with_ports(["8080:80", "9090:90"])
.with_volumes([`${work_dir}:/data`, `${config_dir}:/config`])
.with_envs(#{
"ENV1": "value1",
"ENV2": "value2",
"TEST_MODE": "true"
})
.with_network("bridge")
.with_cpu_limit("0.5")
.with_memory_limit("256m");
// Verify container properties
assert_eq(container.name, container_name, "Container name should match");
assert_eq(container.image, "alpine:latest", "Container image should match");
assert_true(container.detach, "Container detach mode should be true");
// Run the container
print("Testing run() with builder pattern...");
let run_result = container.run();
assert_true(run_result.success, "Container run should succeed");
assert_true(container.container_id != "", "Container ID should not be empty after run");
print(`✓ run(): Container started with ID: ${container.container_id}`);
// Test environment variables
print("Testing environment variables...");
let env_result = container.exec("env");
assert_true(env_result.success, "Container exec should succeed");
assert_true(env_result.stdout.contains("ENV1=value1"), "Environment variable ENV1 should be set");
assert_true(env_result.stdout.contains("ENV2=value2"), "Environment variable ENV2 should be set");
assert_true(env_result.stdout.contains("TEST_MODE=true"), "Environment variable TEST_MODE should be set");
print("✓ Environment variables set correctly");
// Test volume mounts
print("Testing volume mounts...");
// Create a test file in the work directory
file_write(`${work_dir}/test.txt`, "Hello from host");
// Check if the file is accessible in the container
let volume_result = container.exec("cat /data/test.txt");
assert_true(volume_result.success, "Container exec should succeed");
assert_true(volume_result.stdout.contains("Hello from host"), "Volume mount should work correctly");
print("✓ Volume mounts working correctly");
// Test writing from container to volume
print("Testing writing from container to volume...");
let write_result = container.exec("echo 'Hello from container' > /config/container.txt");
assert_true(write_result.success, "Container exec should succeed");
// Check if the file was created on the host
let host_file_content = file_read(`${config_dir}/container.txt`);
assert_true(host_file_content.contains("Hello from container"), "Container should be able to write to volume");
print("✓ Container can write to volume");
// Test stopping the container
print("Testing stop()...");
let stop_result = container.stop();
assert_true(stop_result.success, "Container stop should succeed");
print("✓ stop(): Container stopped successfully");
// Test removing the container
print("Testing remove()...");
let remove_result = container.remove();
assert_true(remove_result.success, "Container remove should succeed");
print("✓ remove(): Container removed successfully");
print("All container builder pattern tests completed successfully!");
} catch(err) {
print(`Error: ${err}`);
// Clean up in case of error
cleanup_container(container_name);
throw err;
} finally {
// Clean up test directories
delete(work_dir);
delete(config_dir);
print("✓ Cleanup: Test directories removed");
}

View File

@@ -1,183 +0,0 @@
// run_all_tests.rhai
// Runs all Nerdctl module tests
print("=== Running Nerdctl Module Tests ===");
// Custom assert function
fn assert_true(condition, message) {
if !condition {
print(`ASSERTION FAILED: ${message}`);
throw message;
}
}
// Helper function to check if nerdctl is available
fn is_nerdctl_available() {
try {
let result = run("which nerdctl");
return result.success;
} catch(e) {
return false;
}
}
// Helper function to clean up a container if it exists
fn cleanup_container(container_name) {
try {
run(`nerdctl stop ${container_name}`);
run(`nerdctl rm ${container_name}`);
} catch(e) {
// Ignore errors during cleanup
}
}
// Run each test directly
let passed = 0;
let failed = 0;
let skipped = 0;
let total = 0;
// Check if nerdctl is available
let nerdctl_available = is_nerdctl_available();
if !nerdctl_available {
print("nerdctl is not available. Skipping all Nerdctl tests.");
skipped = 3; // Skip all three tests
total = 3;
} else {
// Test 1: Container Operations
print("\n--- Running Container Operations Tests ---");
try {
// Define test container name
let container_name = "rhai_test_container";
// Clean up any existing test container
cleanup_container(container_name);
// Create a new Container
let container = nerdctl_container_new(container_name);
// Set container image
container.with_image("alpine:latest");
// Set detach mode
container.with_detach(true);
// Run the container
let run_result = container.run();
assert_true(run_result.success, "Container run should succeed");
// Execute a command in the container
let exec_result = container.exec("echo 'Hello from container'");
assert_true(exec_result.success, "Container exec should succeed");
// Clean up
container.stop();
container.remove();
print("--- Container Operations Tests completed successfully ---");
passed += 1;
} catch(err) {
print(`!!! Error in Container Operations Tests: ${err}`);
failed += 1;
// Clean up in case of error
cleanup_container("rhai_test_container");
}
total += 1;
// Test 2: Image Operations
print("\n--- Running Image Operations Tests ---");
try {
// Create a temporary directory for testing
let test_dir = "rhai_test_nerdctl";
mkdir(test_dir);
// Pull a small image for testing
let pull_result = nerdctl_image_pull("alpine:latest");
assert_true(pull_result.success, "Image pull should succeed");
// List images
let images_result = nerdctl_images();
assert_true(images_result.success, "Image listing should succeed");
// Clean up
delete(test_dir);
print("--- Image Operations Tests completed successfully ---");
passed += 1;
} catch(err) {
print(`!!! Error in Image Operations Tests: ${err}`);
failed += 1;
// Clean up in case of error
try {
delete("rhai_test_nerdctl");
} catch(e) {
// Ignore errors during cleanup
}
}
total += 1;
// Test 3: Container Builder Pattern
print("\n--- Running Container Builder Pattern Tests ---");
try {
// Define test container name
let container_name = "rhai_test_builder";
// Clean up any existing test container
cleanup_container(container_name);
// Create test directory
let work_dir = "rhai_test_nerdctl_work";
mkdir(work_dir);
// Create a container with builder pattern
let container = nerdctl_container_from_image(container_name, "alpine:latest")
.reset()
.with_detach(true)
.with_volumes([`${work_dir}:/data`]);
// Run the container
let run_result = container.run();
assert_true(run_result.success, "Container run should succeed");
// Clean up
container.stop();
container.remove();
delete(work_dir);
print("--- Container Builder Pattern Tests completed successfully ---");
passed += 1;
} catch(err) {
print(`!!! Error in Container Builder Pattern Tests: ${err}`);
failed += 1;
// Clean up in case of error
cleanup_container("rhai_test_builder");
try {
delete("rhai_test_nerdctl_work");
} catch(e) {
// Ignore errors during cleanup
}
}
total += 1;
}
print("\n=== Test Summary ===");
print(`Passed: ${passed}`);
print(`Failed: ${failed}`);
print(`Skipped: ${skipped}`);
print(`Total: ${total}`);
if failed == 0 {
if skipped > 0 {
print("\n⚠ All tests skipped or passed!");
} else {
print("\n✅ All tests passed!");
}
} else {
print("\n❌ Some tests failed!");
}
// Return the number of failed tests (0 means success)
failed;

View File

@@ -1,111 +0,0 @@
// 01_file_operations.rhai
// Tests for file system operations in the OS module
// Custom assert function
fn assert_true(condition, message) {
if !condition {
print(`ASSERTION FAILED: ${message}`);
throw message;
}
}
// Create a test directory structure
let test_dir = "rhai_test_fs";
let sub_dir = test_dir + "/subdir";
// Test mkdir function
print("Testing mkdir...");
let mkdir_result = mkdir(test_dir);
assert_true(exist(test_dir), "Directory creation failed");
print(`✓ mkdir: ${mkdir_result}`);
// Test nested directory creation
let nested_result = mkdir(sub_dir);
assert_true(exist(sub_dir), "Nested directory creation failed");
print(`✓ mkdir (nested): ${nested_result}`);
// Test file_write function
let test_file = test_dir + "/test.txt";
let file_content = "This is a test file created by Rhai test script.";
let write_result = file_write(test_file, file_content);
assert_true(exist(test_file), "File creation failed");
print(`✓ file_write: ${write_result}`);
// Test file_read function
let read_content = file_read(test_file);
assert_true(read_content == file_content, "File content doesn't match");
print(`✓ file_read: Content matches`);
// Test file_size function
let size = file_size(test_file);
assert_true(size > 0, "File size should be greater than 0");
print(`✓ file_size: ${size} bytes`);
// Test file_write_append function
let append_content = "\nThis is appended content.";
let append_result = file_write_append(test_file, append_content);
let new_content = file_read(test_file);
assert_true(new_content == file_content + append_content, "Appended content doesn't match");
print(`✓ file_write_append: ${append_result}`);
// Test copy function
let copied_file = test_dir + "/copied.txt";
let copy_result = copy(test_file, copied_file);
assert_true(exist(copied_file), "File copy failed");
print(`✓ copy: ${copy_result}`);
// Test mv function
let moved_file = test_dir + "/moved.txt";
let mv_result = mv(copied_file, moved_file);
assert_true(exist(moved_file), "File move failed");
assert_true(!exist(copied_file), "Source file still exists after move");
print(`✓ mv: ${mv_result}`);
// Test find_file function
let found_file = find_file(test_dir, "*.txt");
assert_true(found_file.contains("test.txt") || found_file.contains("moved.txt"), "find_file failed");
print(`✓ find_file: ${found_file}`);
// Test find_files function
let found_files = find_files(test_dir, "*.txt");
assert_true(found_files.len() == 2, "find_files should find 2 files");
print(`✓ find_files: Found ${found_files.len()} files`);
// Test find_dir function
let found_dir = find_dir(test_dir, "sub*");
assert_true(found_dir.contains("subdir"), "find_dir failed");
print(`✓ find_dir: ${found_dir}`);
// Test find_dirs function
let found_dirs = find_dirs(test_dir, "sub*");
assert_true(found_dirs.len() == 1, "find_dirs should find 1 directory");
print(`✓ find_dirs: Found ${found_dirs.len()} directories`);
// Test chdir function
// Save current directory path before changing
let chdir_result = chdir(test_dir);
print(`✓ chdir: ${chdir_result}`);
// Change back to parent directory
chdir("..");
// Test rsync function (if available)
let rsync_dir = test_dir + "/rsync_dest";
mkdir(rsync_dir);
let rsync_result = rsync(test_dir, rsync_dir);
print(`✓ rsync: ${rsync_result}`);
// Test delete function
let delete_file_result = delete(test_file);
assert_true(!exist(test_file), "File deletion failed");
print(`✓ delete (file): ${delete_file_result}`);
// Clean up
delete(moved_file);
delete(sub_dir);
delete(rsync_dir);
delete(test_dir);
assert_true(!exist(test_dir), "Directory deletion failed");
print(`✓ delete (directory): Directory cleaned up`);
print("All file system tests completed successfully!");

View File

@@ -1,53 +0,0 @@
// 02_download_operations.rhai
// Tests for download operations in the OS module
// Custom assert function
fn assert_true(condition, message) {
if !condition {
print(`ASSERTION FAILED: ${message}`);
throw message;
}
}
// Create a test directory
let test_dir = "rhai_test_download";
mkdir(test_dir);
print(`Created test directory: ${test_dir}`);
// Test which function to ensure curl is available
let curl_path = which("curl");
if curl_path == "" {
print("Warning: curl not found, download tests may fail");
} else {
print(`✓ which: curl found at ${curl_path}`);
}
// Test cmd_ensure_exists function
let ensure_result = cmd_ensure_exists("curl");
print(`✓ cmd_ensure_exists: ${ensure_result}`);
// Test download function with a small file
let download_url = "https://raw.githubusercontent.com/rust-lang/rust/master/LICENSE-MIT";
let download_dest = test_dir + "/license.txt";
let min_size_kb = 1; // Minimum size in KB
print(`Downloading ${download_url}...`);
let download_result = download_file(download_url, download_dest, min_size_kb);
assert_true(exist(download_dest), "Download failed");
print(`✓ download_file: ${download_result}`);
// Verify the downloaded file
let file_content = file_read(download_dest);
assert_true(file_content.contains("Permission is hereby granted"), "Downloaded file content is incorrect");
print("✓ Downloaded file content verified");
// Test chmod_exec function
let chmod_result = chmod_exec(download_dest);
print(`✓ chmod_exec: ${chmod_result}`);
// Clean up
delete(test_dir);
assert_true(!exist(test_dir), "Directory deletion failed");
print(`✓ Cleanup: Directory ${test_dir} removed`);
print("All download tests completed successfully!");

View File

@@ -1,56 +0,0 @@
// 03_package_operations.rhai
// Tests for package management operations in the OS module
// Custom assert function
fn assert_true(condition, message) {
if !condition {
print(`ASSERTION FAILED: ${message}`);
throw message;
}
}
// Test package_platform function
let platform = package_platform();
print(`Current platform: ${platform}`);
// Test package_set_debug function
let debug_enabled = package_set_debug(true);
assert_true(debug_enabled, "Debug mode should be enabled");
print("✓ package_set_debug: Debug mode enabled");
// Disable debug mode for remaining tests
package_set_debug(false);
// Test package_is_installed function with a package that should exist on most systems
let common_packages = ["bash", "curl", "grep"];
let found_package = false;
for pkg in common_packages {
let is_installed = package_is_installed(pkg);
if is_installed {
print(`✓ package_is_installed: ${pkg} is installed`);
found_package = true;
break;
}
}
if !found_package {
print("Warning: None of the common packages were found installed");
}
// Test package_search function with a common term
// Note: This might be slow and produce a lot of output
print("Testing package_search (this might take a moment)...");
let search_results = package_search("lib");
print(`✓ package_search: Found ${search_results.len()} packages containing 'lib'`);
// Test package_list function
// Note: This might be slow and produce a lot of output
print("Testing package_list (this might take a moment)...");
let installed_packages = package_list();
print(`✓ package_list: Found ${installed_packages.len()} installed packages`);
// Note: We're not testing package_install, package_remove, package_update, or package_upgrade
// as they require root privileges and could modify the system state
print("All package management tests completed successfully!");

View File

@@ -1,148 +0,0 @@
// run_all_tests.rhai
// Runs all OS module tests
print("=== Running OS Module Tests ===");
// Custom assert function
fn assert_true(condition, message) {
if !condition {
print(`ASSERTION FAILED: ${message}`);
throw message;
}
}
// Run each test directly
let passed = 0;
let failed = 0;
// Test 1: File Operations
print("\n--- Running File Operations Tests ---");
try {
// Create a test directory structure
let test_dir = "rhai_test_fs";
let sub_dir = test_dir + "/subdir";
// Test mkdir function
print("Testing mkdir...");
let mkdir_result = mkdir(test_dir);
assert_true(exist(test_dir), "Directory creation failed");
print(`✓ mkdir: ${mkdir_result}`);
// Test nested directory creation
let nested_result = mkdir(sub_dir);
assert_true(exist(sub_dir), "Nested directory creation failed");
print(`✓ mkdir (nested): ${nested_result}`);
// Test file_write function
let test_file = test_dir + "/test.txt";
let file_content = "This is a test file created by Rhai test script.";
let write_result = file_write(test_file, file_content);
assert_true(exist(test_file), "File creation failed");
print(`✓ file_write: ${write_result}`);
// Test file_read function
let read_content = file_read(test_file);
assert_true(read_content == file_content, "File content doesn't match");
print(`✓ file_read: Content matches`);
// Test file_size function
let size = file_size(test_file);
assert_true(size > 0, "File size should be greater than 0");
print(`✓ file_size: ${size} bytes`);
// Clean up
delete(test_file);
delete(sub_dir);
delete(test_dir);
assert_true(!exist(test_dir), "Directory deletion failed");
print(`✓ delete: Directory cleaned up`);
print("--- File Operations Tests completed successfully ---");
passed += 1;
} catch(err) {
print(`!!! Error in File Operations Tests: ${err}`);
failed += 1;
}
// Test 2: Download Operations
print("\n--- Running Download Operations Tests ---");
try {
// Create a test directory
let test_dir = "rhai_test_download";
mkdir(test_dir);
print(`Created test directory: ${test_dir}`);
// Test which function to ensure curl is available
let curl_path = which("curl");
if curl_path == "" {
print("Warning: curl not found, download tests may fail");
} else {
print(`✓ which: curl found at ${curl_path}`);
}
// Test cmd_ensure_exists function
let ensure_result = cmd_ensure_exists("curl");
print(`✓ cmd_ensure_exists: ${ensure_result}`);
// Test download function with a small file
let download_url = "https://raw.githubusercontent.com/rust-lang/rust/master/LICENSE-MIT";
let download_dest = test_dir + "/license.txt";
let min_size_kb = 1; // Minimum size in KB
print(`Downloading ${download_url}...`);
let download_result = download_file(download_url, download_dest, min_size_kb);
assert_true(exist(download_dest), "Download failed");
print(`✓ download_file: ${download_result}`);
// Verify the downloaded file
let file_content = file_read(download_dest);
assert_true(file_content.contains("Permission is hereby granted"), "Downloaded file content is incorrect");
print("✓ Downloaded file content verified");
// Clean up
delete(test_dir);
assert_true(!exist(test_dir), "Directory deletion failed");
print(`✓ Cleanup: Directory ${test_dir} removed`);
print("--- Download Operations Tests completed successfully ---");
passed += 1;
} catch(err) {
print(`!!! Error in Download Operations Tests: ${err}`);
failed += 1;
}
// Test 3: Package Operations
print("\n--- Running Package Operations Tests ---");
try {
// Test package_platform function
let platform = package_platform();
print(`Current platform: ${platform}`);
// Test package_set_debug function
let debug_enabled = package_set_debug(true);
assert_true(debug_enabled, "Debug mode should be enabled");
print("✓ package_set_debug: Debug mode enabled");
// Disable debug mode for remaining tests
package_set_debug(false);
print("--- Package Operations Tests completed successfully ---");
passed += 1;
} catch(err) {
print(`!!! Error in Package Operations Tests: ${err}`);
failed += 1;
}
print("\n=== Test Summary ===");
print(`Passed: ${passed}`);
print(`Failed: ${failed}`);
print(`Total: ${passed + failed}`);
if failed == 0 {
print("\n✅ All tests passed!");
} else {
print("\n❌ Some tests failed!");
}
// Return the number of failed tests (0 means success)
failed;

View File

@@ -1,106 +0,0 @@
// 01_postgres_connection.rhai
// Tests for PostgreSQL client connection and basic operations
// Custom assert function
fn assert_true(condition, message) {
if !condition {
print(`ASSERTION FAILED: ${message}`);
throw message;
}
}
// Helper function to check if PostgreSQL is available
fn is_postgres_available() {
try {
// Try to execute a simple connection
let connect_result = pg_connect();
return connect_result;
} catch(err) {
print(`PostgreSQL connection error: ${err}`);
return false;
}
}
print("=== Testing PostgreSQL Client Connection ===");
// Check if PostgreSQL is available
let postgres_available = is_postgres_available();
if !postgres_available {
print("PostgreSQL server is not available. Skipping PostgreSQL tests.");
// Exit gracefully without error
return;
}
print("✓ PostgreSQL server is available");
// Test pg_ping function
print("Testing pg_ping()...");
let ping_result = pg_ping();
assert_true(ping_result, "PING should return true");
print(`✓ pg_ping(): Returned ${ping_result}`);
// Test pg_execute function
print("Testing pg_execute()...");
let test_table = "rhai_test_table";
// Create a test table
let create_table_query = `
CREATE TABLE IF NOT EXISTS ${test_table} (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
value INTEGER
)
`;
let create_result = pg_execute(create_table_query);
assert_true(create_result >= 0, "CREATE TABLE operation should succeed");
print(`✓ pg_execute(): Successfully created table ${test_table}`);
// Insert a test row
let insert_query = `
INSERT INTO ${test_table} (name, value)
VALUES ('test_name', 42)
`;
let insert_result = pg_execute(insert_query);
assert_true(insert_result > 0, "INSERT operation should succeed");
print(`✓ pg_execute(): Successfully inserted row into ${test_table}`);
// Test pg_query function
print("Testing pg_query()...");
let select_query = `
SELECT * FROM ${test_table}
`;
let select_result = pg_query(select_query);
assert_true(select_result.len() > 0, "SELECT should return at least one row");
print(`✓ pg_query(): Successfully retrieved ${select_result.len()} rows from ${test_table}`);
// Test pg_query_one function
print("Testing pg_query_one()...");
let select_one_query = `
SELECT * FROM ${test_table} LIMIT 1
`;
let select_one_result = pg_query_one(select_one_query);
assert_true(select_one_result["name"] == "test_name", "SELECT ONE should return the correct name");
assert_true(select_one_result["value"] == "42", "SELECT ONE should return the correct value");
print(`✓ pg_query_one(): Successfully retrieved row with name=${select_one_result["name"]} and value=${select_one_result["value"]}`);
// Clean up
print("Cleaning up...");
let drop_table_query = `
DROP TABLE IF EXISTS ${test_table}
`;
let drop_result = pg_execute(drop_table_query);
assert_true(drop_result >= 0, "DROP TABLE operation should succeed");
print(`✓ pg_execute(): Successfully dropped table ${test_table}`);
// Test pg_reset function
print("Testing pg_reset()...");
let reset_result = pg_reset();
assert_true(reset_result, "RESET should return true");
print(`✓ pg_reset(): Successfully reset PostgreSQL client`);
print("All PostgreSQL connection tests completed successfully!");

View File

@@ -1,164 +0,0 @@
// PostgreSQL Installer Test
//
// This test script demonstrates how to use the PostgreSQL installer module to:
// - Install PostgreSQL using nerdctl
// - Create a database
// - Execute SQL scripts
// - Check if PostgreSQL is running
//
// Prerequisites:
// - nerdctl must be installed and working
// - Docker images must be accessible
// Define utility functions
fn assert_true(condition, message) {
if !condition {
print(`ASSERTION FAILED: ${message}`);
throw message;
}
}
// Define test variables (will be used inside the test function)
// Function to check if nerdctl is available
fn is_nerdctl_available() {
try {
// For testing purposes, we'll assume nerdctl is not available
// In a real-world scenario, you would check if nerdctl is installed
return false;
} catch {
return false;
}
}
// Function to clean up any existing PostgreSQL container
fn cleanup_postgres() {
try {
// In a real-world scenario, you would use nerdctl to stop and remove the container
// For this test, we'll just print a message
print("Cleaned up existing PostgreSQL container (simulated)");
} catch {
// Ignore errors if container doesn't exist
}
}
// Main test function
fn run_postgres_installer_test() {
print("\n=== PostgreSQL Installer Test ===");
// Define test variables
let container_name = "postgres-test";
let postgres_version = "15";
let postgres_port = 5433; // Use a non-default port to avoid conflicts
let postgres_user = "testuser";
let postgres_password = "testpassword";
let test_db_name = "testdb";
// // Check if nerdctl is available
// if !is_nerdctl_available() {
// print("nerdctl is not available. Skipping PostgreSQL installer test.");
// return 1; // Skip the test
// }
// Clean up any existing PostgreSQL container
cleanup_postgres();
// Test 1: Install PostgreSQL
print("\n1. Installing PostgreSQL...");
try {
let install_result = pg_install(
container_name,
postgres_version,
postgres_port,
postgres_user,
postgres_password
);
assert_true(install_result, "PostgreSQL installation should succeed");
print("✓ PostgreSQL installed successfully");
// Wait a bit for PostgreSQL to fully initialize
print("Waiting for PostgreSQL to initialize...");
// In a real-world scenario, you would wait for PostgreSQL to initialize
// For this test, we'll just print a message
print("Waited for PostgreSQL to initialize (simulated)")
} catch(e) {
print(`✗ Failed to install PostgreSQL: ${e}`);
cleanup_postgres();
return 1; // Test failed
}
// Test 2: Check if PostgreSQL is running
print("\n2. Checking if PostgreSQL is running...");
try {
let running = pg_is_running(container_name);
assert_true(running, "PostgreSQL should be running");
print("✓ PostgreSQL is running");
} catch(e) {
print(`✗ Failed to check if PostgreSQL is running: ${e}`);
cleanup_postgres();
return 1; // Test failed
}
// Test 3: Create a database
print("\n3. Creating a database...");
try {
let create_result = pg_create_database(container_name, test_db_name);
assert_true(create_result, "Database creation should succeed");
print(`✓ Database '${test_db_name}' created successfully`);
} catch(e) {
print(`✗ Failed to create database: ${e}`);
cleanup_postgres();
return 1; // Test failed
}
// Test 4: Execute SQL script
print("\n4. Executing SQL script...");
try {
// Create a table
let create_table_sql = `
CREATE TABLE test_table (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
value INTEGER
);
`;
let result = pg_execute_sql(container_name, test_db_name, create_table_sql);
print("✓ Created table successfully");
// Insert data
let insert_sql = `
INSERT INTO test_table (name, value) VALUES
('test1', 100),
('test2', 200),
('test3', 300);
`;
result = pg_execute_sql(container_name, test_db_name, insert_sql);
print("✓ Inserted data successfully");
// Query data
let query_sql = "SELECT * FROM test_table ORDER BY id;";
result = pg_execute_sql(container_name, test_db_name, query_sql);
print("✓ Queried data successfully");
print(`Query result: ${result}`);
} catch(e) {
print(`✗ Failed to execute SQL script: ${e}`);
cleanup_postgres();
return 1; // Test failed
}
// Clean up
print("\nCleaning up...");
cleanup_postgres();
print("\n=== PostgreSQL Installer Test Completed Successfully ===");
return 0; // Test passed
}
// Run the test
let result = run_postgres_installer_test();
// Return the result
result

View File

@@ -1,61 +0,0 @@
// PostgreSQL Installer Test (Mock)
//
// This test script simulates the PostgreSQL installer module tests
// without actually calling the PostgreSQL functions.
// Define utility functions
fn assert_true(condition, message) {
if !condition {
print(`ASSERTION FAILED: ${message}`);
throw message;
}
}
// Main test function
fn run_postgres_installer_test() {
print("\n=== PostgreSQL Installer Test (Mock) ===");
// Define test variables
let container_name = "postgres-test";
let postgres_version = "15";
let postgres_port = 5433; // Use a non-default port to avoid conflicts
let postgres_user = "testuser";
let postgres_password = "testpassword";
let test_db_name = "testdb";
// Clean up any existing PostgreSQL container
print("Cleaned up existing PostgreSQL container (simulated)");
// Test 1: Install PostgreSQL
print("\n1. Installing PostgreSQL...");
print("✓ PostgreSQL installed successfully (simulated)");
print("Waited for PostgreSQL to initialize (simulated)");
// Test 2: Check if PostgreSQL is running
print("\n2. Checking if PostgreSQL is running...");
print("✓ PostgreSQL is running (simulated)");
// Test 3: Create a database
print("\n3. Creating a database...");
print(`✓ Database '${test_db_name}' created successfully (simulated)`);
// Test 4: Execute SQL script
print("\n4. Executing SQL script...");
print("✓ Created table successfully (simulated)");
print("✓ Inserted data successfully (simulated)");
print("✓ Queried data successfully (simulated)");
print("Query result: (simulated results)");
// Clean up
print("\nCleaning up...");
print("Cleaned up existing PostgreSQL container (simulated)");
print("\n=== PostgreSQL Installer Test Completed Successfully ===");
return 0; // Test passed
}
// Run the test
let result = run_postgres_installer_test();
// Return the result
result

View File

@@ -1,101 +0,0 @@
// PostgreSQL Installer Test (Simplified)
//
// This test script demonstrates how to use the PostgreSQL installer module to:
// - Install PostgreSQL using nerdctl
// - Create a database
// - Execute SQL scripts
// - Check if PostgreSQL is running
// Define test variables
let container_name = "postgres-test";
let postgres_version = "15";
let postgres_port = 5433; // Use a non-default port to avoid conflicts
let postgres_user = "testuser";
let postgres_password = "testpassword";
let test_db_name = "testdb";
// Main test function
fn test_postgres_installer() {
print("\n=== PostgreSQL Installer Test ===");
// Test 1: Install PostgreSQL
print("\n1. Installing PostgreSQL...");
try {
let install_result = pg_install(
container_name,
postgres_version,
postgres_port,
postgres_user,
postgres_password
);
print(`PostgreSQL installation result: ${install_result}`);
print("✓ PostgreSQL installed successfully");
} catch(e) {
print(`✗ Failed to install PostgreSQL: ${e}`);
return;
}
// Test 2: Check if PostgreSQL is running
print("\n2. Checking if PostgreSQL is running...");
try {
let running = pg_is_running(container_name);
print(`PostgreSQL running status: ${running}`);
print("✓ PostgreSQL is running");
} catch(e) {
print(`✗ Failed to check if PostgreSQL is running: ${e}`);
return;
}
// Test 3: Create a database
print("\n3. Creating a database...");
try {
let create_result = pg_create_database(container_name, test_db_name);
print(`Database creation result: ${create_result}`);
print(`✓ Database '${test_db_name}' created successfully`);
} catch(e) {
print(`✗ Failed to create database: ${e}`);
return;
}
// Test 4: Execute SQL script
print("\n4. Executing SQL script...");
try {
// Create a table
let create_table_sql = `
CREATE TABLE test_table (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
value INTEGER
);
`;
let result = pg_execute_sql(container_name, test_db_name, create_table_sql);
print("✓ Created table successfully");
// Insert data
let insert_sql = `
INSERT INTO test_table (name, value) VALUES
('test1', 100),
('test2', 200),
('test3', 300);
`;
result = pg_execute_sql(container_name, test_db_name, insert_sql);
print("✓ Inserted data successfully");
// Query data
let query_sql = "SELECT * FROM test_table ORDER BY id;";
result = pg_execute_sql(container_name, test_db_name, query_sql);
print("✓ Queried data successfully");
print(`Query result: ${result}`);
} catch(e) {
print(`✗ Failed to execute SQL script: ${e}`);
return;
}
print("\n=== PostgreSQL Installer Test Completed Successfully ===");
}
// Run the test
test_postgres_installer();

View File

@@ -1,82 +0,0 @@
// PostgreSQL Installer Example
//
// This example demonstrates how to use the PostgreSQL installer module to:
// - Install PostgreSQL using nerdctl
// - Create a database
// - Execute SQL scripts
// - Check if PostgreSQL is running
//
// Prerequisites:
// - nerdctl must be installed and working
// - Docker images must be accessible
// Define variables
let container_name = "postgres-example";
let postgres_version = "15";
let postgres_port = 5432;
let postgres_user = "exampleuser";
let postgres_password = "examplepassword";
let db_name = "exampledb";
// Install PostgreSQL
print("Installing PostgreSQL...");
try {
let install_result = pg_install(
container_name,
postgres_version,
postgres_port,
postgres_user,
postgres_password
);
print("PostgreSQL installed successfully!");
// Check if PostgreSQL is running
print("\nChecking if PostgreSQL is running...");
let running = pg_is_running(container_name);
if (running) {
print("PostgreSQL is running!");
// Create a database
print("\nCreating a database...");
let create_result = pg_create_database(container_name, db_name);
print(`Database '${db_name}' created successfully!`);
// Create a table
print("\nCreating a table...");
let create_table_sql = `
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
email TEXT UNIQUE NOT NULL
);
`;
let result = pg_execute_sql(container_name, db_name, create_table_sql);
print("Table created successfully!");
// Insert data
print("\nInserting data...");
let insert_sql = `
INSERT INTO users (name, email) VALUES
('John Doe', 'john@example.com'),
('Jane Smith', 'jane@example.com');
`;
result = pg_execute_sql(container_name, db_name, insert_sql);
print("Data inserted successfully!");
// Query data
print("\nQuerying data...");
let query_sql = "SELECT * FROM users;";
result = pg_execute_sql(container_name, db_name, query_sql);
print(`Query result: ${result}`);
} else {
print("PostgreSQL is not running!");
}
} catch(e) {
print(`Error: ${e}`);
}
print("\nExample completed!");

View File

@@ -1,159 +0,0 @@
// run_all_tests.rhai
// Runs all PostgreSQL client module tests
print("=== Running PostgreSQL Client Module Tests ===");
// Custom assert function
fn assert_true(condition, message) {
if !condition {
print(`ASSERTION FAILED: ${message}`);
throw message;
}
}
// Helper function to check if PostgreSQL is available
fn is_postgres_available() {
try {
// Try to execute a simple connection
let connect_result = pg_connect();
return connect_result;
} catch(err) {
print(`PostgreSQL connection error: ${err}`);
return false;
}
}
// Helper function to check if nerdctl is available
fn is_nerdctl_available() {
try {
// For testing purposes, we'll assume nerdctl is not available
// In a real-world scenario, you would check if nerdctl is installed
return false;
} catch {
return false;
}
}
// Run each test directly
let passed = 0;
let failed = 0;
let skipped = 0;
// Check if PostgreSQL is available
let postgres_available = is_postgres_available();
if !postgres_available {
print("PostgreSQL server is not available. Skipping basic PostgreSQL tests.");
skipped += 1; // Skip the test
} else {
// Test 1: PostgreSQL Connection
print("\n--- Running PostgreSQL Connection Tests ---");
try {
// Test pg_ping function
print("Testing pg_ping()...");
let ping_result = pg_ping();
assert_true(ping_result, "PING should return true");
print(`✓ pg_ping(): Returned ${ping_result}`);
// Test pg_execute function
print("Testing pg_execute()...");
let test_table = "rhai_test_table";
// Create a test table
let create_table_query = `
CREATE TABLE IF NOT EXISTS ${test_table} (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
value INTEGER
)
`;
let create_result = pg_execute(create_table_query);
assert_true(create_result >= 0, "CREATE TABLE operation should succeed");
print(`✓ pg_execute(): Successfully created table ${test_table}`);
// Insert a test row
let insert_query = `
INSERT INTO ${test_table} (name, value)
VALUES ('test_name', 42)
`;
let insert_result = pg_execute(insert_query);
assert_true(insert_result > 0, "INSERT operation should succeed");
print(`✓ pg_execute(): Successfully inserted row into ${test_table}`);
// Test pg_query function
print("Testing pg_query()...");
let select_query = `
SELECT * FROM ${test_table}
`;
let select_result = pg_query(select_query);
assert_true(select_result.len() > 0, "SELECT should return at least one row");
print(`✓ pg_query(): Successfully retrieved ${select_result.len()} rows from ${test_table}`);
// Clean up
print("Cleaning up...");
let drop_table_query = `
DROP TABLE IF EXISTS ${test_table}
`;
let drop_result = pg_execute(drop_table_query);
assert_true(drop_result >= 0, "DROP TABLE operation should succeed");
print(`✓ pg_execute(): Successfully dropped table ${test_table}`);
print("--- PostgreSQL Connection Tests completed successfully ---");
passed += 1;
} catch(err) {
print(`!!! Error in PostgreSQL Connection Tests: ${err}`);
failed += 1;
}
}
// Test 2: PostgreSQL Installer
// Check if nerdctl is available
let nerdctl_available = is_nerdctl_available();
if !nerdctl_available {
print("nerdctl is not available. Running mock PostgreSQL installer tests.");
try {
// Run the mock installer test
let installer_test_result = 0; // Simulate success
print("\n--- Running PostgreSQL Installer Tests (Mock) ---");
print("✓ PostgreSQL installed successfully (simulated)");
print("✓ Database created successfully (simulated)");
print("✓ SQL executed successfully (simulated)");
print("--- PostgreSQL Installer Tests completed successfully (simulated) ---");
passed += 1;
} catch(err) {
print(`!!! Error in PostgreSQL Installer Tests: ${err}`);
failed += 1;
}
} else {
print("\n--- Running PostgreSQL Installer Tests ---");
try {
// For testing purposes, we'll assume the installer tests pass
print("--- PostgreSQL Installer Tests completed successfully ---");
passed += 1;
} catch(err) {
print(`!!! Error in PostgreSQL Installer Tests: ${err}`);
failed += 1;
}
}
print("\n=== Test Summary ===");
print(`Passed: ${passed}`);
print(`Failed: ${failed}`);
print(`Skipped: ${skipped}`);
print(`Total: ${passed + failed + skipped}`);
if failed == 0 {
if skipped > 0 {
print("\n⚠ All tests skipped or passed!");
} else {
print("\n✅ All tests passed!");
}
} else {
print("\n❌ Some tests failed!");
}
// Return the number of failed tests (0 means success)
failed;

View File

@@ -1,93 +0,0 @@
// Test script to check if the PostgreSQL functions are registered
// Try to call the basic PostgreSQL functions
try {
print("Trying to call pg_connect()...");
let result = pg_connect();
print("pg_connect result: " + result);
} catch(e) {
print("Error calling pg_connect: " + e);
}
// Try to call the pg_ping function
try {
print("\nTrying to call pg_ping()...");
let result = pg_ping();
print("pg_ping result: " + result);
} catch(e) {
print("Error calling pg_ping: " + e);
}
// Try to call the pg_reset function
try {
print("\nTrying to call pg_reset()...");
let result = pg_reset();
print("pg_reset result: " + result);
} catch(e) {
print("Error calling pg_reset: " + e);
}
// Try to call the pg_execute function
try {
print("\nTrying to call pg_execute()...");
let result = pg_execute("SELECT 1");
print("pg_execute result: " + result);
} catch(e) {
print("Error calling pg_execute: " + e);
}
// Try to call the pg_query function
try {
print("\nTrying to call pg_query()...");
let result = pg_query("SELECT 1");
print("pg_query result: " + result);
} catch(e) {
print("Error calling pg_query: " + e);
}
// Try to call the pg_query_one function
try {
print("\nTrying to call pg_query_one()...");
let result = pg_query_one("SELECT 1");
print("pg_query_one result: " + result);
} catch(e) {
print("Error calling pg_query_one: " + e);
}
// Try to call the pg_install function
try {
print("\nTrying to call pg_install()...");
let result = pg_install("postgres-test", "15", 5433, "testuser", "testpassword");
print("pg_install result: " + result);
} catch(e) {
print("Error calling pg_install: " + e);
}
// Try to call the pg_create_database function
try {
print("\nTrying to call pg_create_database()...");
let result = pg_create_database("postgres-test", "testdb");
print("pg_create_database result: " + result);
} catch(e) {
print("Error calling pg_create_database: " + e);
}
// Try to call the pg_execute_sql function
try {
print("\nTrying to call pg_execute_sql()...");
let result = pg_execute_sql("postgres-test", "testdb", "SELECT 1");
print("pg_execute_sql result: " + result);
} catch(e) {
print("Error calling pg_execute_sql: " + e);
}
// Try to call the pg_is_running function
try {
print("\nTrying to call pg_is_running()...");
let result = pg_is_running("postgres-test");
print("pg_is_running result: " + result);
} catch(e) {
print("Error calling pg_is_running: " + e);
}
print("\nTest completed!");

View File

@@ -1,24 +0,0 @@
// Simple test script to verify that the Rhai engine is working
print("Hello, world!");
// Try to access the PostgreSQL installer functions
print("\nTrying to access PostgreSQL installer functions...");
// Check if the pg_install function is defined
print("pg_install function is defined: " + is_def_fn("pg_install"));
// Print the available functions
print("\nAvailable functions:");
print("pg_connect: " + is_def_fn("pg_connect"));
print("pg_ping: " + is_def_fn("pg_ping"));
print("pg_reset: " + is_def_fn("pg_reset"));
print("pg_execute: " + is_def_fn("pg_execute"));
print("pg_query: " + is_def_fn("pg_query"));
print("pg_query_one: " + is_def_fn("pg_query_one"));
print("pg_install: " + is_def_fn("pg_install"));
print("pg_create_database: " + is_def_fn("pg_create_database"));
print("pg_execute_sql: " + is_def_fn("pg_execute_sql"));
print("pg_is_running: " + is_def_fn("pg_is_running"));
print("\nTest completed successfully!");

View File

@@ -1,22 +0,0 @@
// Simple test script to verify that the Rhai engine is working
print("Hello, world!");
// Try to access the PostgreSQL installer functions
print("\nTrying to access PostgreSQL installer functions...");
// Try to call the pg_install function
try {
let result = pg_install(
"postgres-test",
"15",
5433,
"testuser",
"testpassword"
);
print("pg_install result: " + result);
} catch(e) {
print("Error calling pg_install: " + e);
}
print("\nTest completed!");

View File

@@ -1,61 +0,0 @@
// 01_command_execution.rhai
// Tests for command execution in the Process module
// Custom assert function
fn assert_true(condition, message) {
if !condition {
print(`ASSERTION FAILED: ${message}`);
throw message;
}
}
print("=== Testing Basic Command Execution ===");
// Test running a simple command
print("Testing run() with a simple command...");
let result = run("echo Hello, World!").execute();
assert_true(result.success, "Command should succeed");
assert_true(result.stdout.contains("Hello, World!"), "Command output should contain the expected text");
print(`✓ run().execute(): Command executed successfully`);
// Test running a command with arguments
print("Testing run() with command arguments...");
let result_with_args = run("echo Hello from Rhai tests").execute();
assert_true(result_with_args.success, "Command with arguments should succeed");
assert_true(result_with_args.stdout.contains("Hello from Rhai tests"), "Command output should contain the expected text");
print(`✓ run().execute(): Command with arguments executed successfully`);
// Test running a command with environment variables
print("Testing run() with environment variables...");
let env_result = run("echo $HOME").execute();
assert_true(env_result.success, "Command with environment variables should succeed");
assert_true(env_result.stdout.trim() != "", "Environment variable should be expanded");
print(`✓ run().execute(): Command with environment variables executed successfully`);
// Test running a multiline script
print("Testing run() with a multiline script...");
let script_result = run(`
echo "Line 1"
echo "Line 2"
echo "Line 3"
`).execute();
assert_true(script_result.success, "Multiline script should succeed");
assert_true(script_result.stdout.contains("Line 1") && script_result.stdout.contains("Line 2") && script_result.stdout.contains("Line 3"),
"Script output should contain all lines");
print(`✓ run().execute(): Multiline script executed successfully`);
// Test which function
print("Testing which() function...");
let bash_path = which("bash");
assert_true(bash_path != "", "bash should be found in PATH");
print(`✓ which(): Found bash at ${bash_path}`);
// Test a command that doesn't exist
let nonexistent_cmd = which("this_command_does_not_exist_12345");
if nonexistent_cmd == "" {
print(`✓ which(): Correctly reported that nonexistent command was not found`);
} else {
print(`Note: Unexpectedly found command at ${nonexistent_cmd}`);
}
print("All command execution tests completed successfully!");

View File

@@ -1,54 +0,0 @@
// 02_process_management.rhai
// Tests for process management functions in the Process module
// Custom assert function
fn assert_true(condition, message) {
if !condition {
print(`ASSERTION FAILED: ${message}`);
throw message;
}
}
print("=== Testing Process Management Functions ===");
// Test process_list function
print("Testing process_list() function...");
let all_processes = process_list("");
assert_true(all_processes.len() > 0, "There should be at least one running process");
print(`✓ process_list(): Found ${all_processes.len()} processes`);
// Test process properties
print("Testing process properties...");
let first_process = all_processes[0];
assert_true(first_process.pid > 0, "Process PID should be a positive number");
assert_true(first_process.name.len() > 0, "Process name should not be empty");
print(`✓ Process properties: PID=${first_process.pid}, Name=${first_process.name}, CPU=${first_process.cpu}%, Memory=${first_process.memory}`);
// Test process_list with a pattern
print("Testing process_list() with a pattern...");
// Use a pattern that's likely to match at least one process on most systems
let pattern = "sh";
let matching_processes = process_list(pattern);
print(`Found ${matching_processes.len()} processes matching '${pattern}'`);
if (matching_processes.len() > 0) {
let matched_process = matching_processes[0];
print(`✓ process_list(pattern): Found process ${matched_process.name} with PID ${matched_process.pid}`);
} else {
print(`Note: No processes found matching '${pattern}'. This is not necessarily an error.`);
}
// Test process_get function
// Note: We'll only test this if we found matching processes above
if (matching_processes.len() == 1) {
print("Testing process_get() function...");
let process = process_get(pattern);
assert_true(process.pid > 0, "Process PID should be a positive number");
assert_true(process.name.contains(pattern), "Process name should contain the pattern");
print(`✓ process_get(): Found process ${process.name} with PID ${process.pid}`);
} else {
print("Skipping process_get() test as it requires exactly one matching process");
}
// Note: We won't test the kill function as it could disrupt the system
print("All process management tests completed successfully!");

View File

@@ -1,76 +0,0 @@
// run_all_tests.rhai
// Runs all Process module tests
print("=== Running Process Module Tests ===");
// Custom assert function
fn assert_true(condition, message) {
if !condition {
print(`ASSERTION FAILED: ${message}`);
throw message;
}
}
// Run each test directly
let passed = 0;
let failed = 0;
// Test 1: Command Execution
print("\n--- Running Command Execution Tests ---");
try {
// Test running a simple command
print("Testing run() with a simple command...");
let result = run("echo Hello, World!").execute();
assert_true(result.success, "Command should succeed");
assert_true(result.stdout.contains("Hello, World!"), "Command output should contain the expected text");
print(`✓ run().execute(): Command executed successfully`);
// Test which function
print("Testing which() function...");
let bash_path = which("bash");
assert_true(bash_path != "", "bash should be found in PATH");
print(`✓ which(): Found bash at ${bash_path}`);
print("--- Command Execution Tests completed successfully ---");
passed += 1;
} catch(err) {
print(`!!! Error in Command Execution Tests: ${err}`);
failed += 1;
}
// Test 2: Process Management
print("\n--- Running Process Management Tests ---");
try {
// Test process_list function
print("Testing process_list() function...");
let all_processes = process_list("");
assert_true(all_processes.len() > 0, "There should be at least one running process");
print(`✓ process_list(): Found ${all_processes.len()} processes`);
// Test process properties
print("Testing process properties...");
let first_process = all_processes[0];
assert_true(first_process.pid > 0, "Process PID should be a positive number");
assert_true(first_process.name.len() > 0, "Process name should not be empty");
print(`✓ Process properties: PID=${first_process.pid}, Name=${first_process.name}`);
print("--- Process Management Tests completed successfully ---");
passed += 1;
} catch(err) {
print(`!!! Error in Process Management Tests: ${err}`);
failed += 1;
}
print("\n=== Test Summary ===");
print(`Passed: ${passed}`);
print(`Failed: ${failed}`);
print(`Total: ${passed + failed}`);
if failed == 0 {
print("\n✅ All tests passed!");
} else {
print("\n❌ Some tests failed!");
}
// Return the number of failed tests (0 means success)
failed;

View File

@@ -1,68 +0,0 @@
// 01_redis_connection.rhai
// Tests for Redis client connection and basic operations
// Custom assert function
fn assert_true(condition, message) {
if !condition {
print(`ASSERTION FAILED: ${message}`);
throw message;
}
}
// Helper function to check if Redis is available
fn is_redis_available() {
try {
// Try to execute a simple PING command
let ping_result = redis_ping();
return ping_result == "PONG";
} catch(err) {
print(`Redis connection error: ${err}`);
return false;
}
}
print("=== Testing Redis Client Connection ===");
// Check if Redis is available
let redis_available = is_redis_available();
if !redis_available {
print("Redis server is not available. Skipping Redis tests.");
// Exit gracefully without error
return;
}
print("✓ Redis server is available");
// Test redis_ping function
print("Testing redis_ping()...");
let ping_result = redis_ping();
assert_true(ping_result == "PONG", "PING should return PONG");
print(`✓ redis_ping(): Returned ${ping_result}`);
// Test redis_set and redis_get functions
print("Testing redis_set() and redis_get()...");
let test_key = "rhai_test_key";
let test_value = "Hello from Rhai test";
// Set a value
let set_result = redis_set(test_key, test_value);
assert_true(set_result, "SET operation should succeed");
print(`✓ redis_set(): Successfully set key ${test_key}`);
// Get the value back
let get_result = redis_get(test_key);
assert_true(get_result == test_value, "GET should return the value we set");
print(`✓ redis_get(): Successfully retrieved value for key ${test_key}`);
// Test redis_del function
print("Testing redis_del()...");
let del_result = redis_del(test_key);
assert_true(del_result, "DEL operation should succeed");
print(`✓ redis_del(): Successfully deleted key ${test_key}`);
// Verify the key was deleted
let get_after_del = redis_get(test_key);
assert_true(get_after_del == "", "Key should not exist after deletion");
print("✓ Key was successfully deleted");
print("All Redis connection tests completed successfully!");

View File

@@ -1,109 +0,0 @@
// 02_redis_operations.rhai
// Tests for advanced Redis operations
// Custom assert function
fn assert_true(condition, message) {
if !condition {
print(`ASSERTION FAILED: ${message}`);
throw message;
}
}
// Helper function to check if Redis is available
fn is_redis_available() {
try {
// Try to execute a simple PING command
let ping_result = redis_ping();
return ping_result == "PONG";
} catch(err) {
print(`Redis connection error: ${err}`);
return false;
}
}
print("=== Testing Advanced Redis Operations ===");
// Check if Redis is available
let redis_available = is_redis_available();
if !redis_available {
print("Redis server is not available. Skipping Redis tests.");
// Exit gracefully without error
return;
}
print("✓ Redis server is available");
// Test prefix for all keys to avoid conflicts
let prefix = "rhai_test_";
// Test redis_hset and redis_hget functions
print("Testing redis_hset() and redis_hget()...");
let hash_key = prefix + "hash";
let field1 = "field1";
let value1 = "value1";
let field2 = "field2";
let value2 = "value2";
// Set hash fields
let hset_result1 = redis_hset(hash_key, field1, value1);
assert_true(hset_result1, "HSET operation should succeed for field1");
let hset_result2 = redis_hset(hash_key, field2, value2);
assert_true(hset_result2, "HSET operation should succeed for field2");
print(`✓ redis_hset(): Successfully set fields in hash ${hash_key}`);
// Get hash fields
let hget_result1 = redis_hget(hash_key, field1);
assert_true(hget_result1 == value1, "HGET should return the value we set for field1");
let hget_result2 = redis_hget(hash_key, field2);
assert_true(hget_result2 == value2, "HGET should return the value we set for field2");
print(`✓ redis_hget(): Successfully retrieved values from hash ${hash_key}`);
// Test redis_hgetall function
print("Testing redis_hgetall()...");
let hgetall_result = redis_hgetall(hash_key);
assert_true(hgetall_result.len() == 2, "HGETALL should return 2 fields");
assert_true(hgetall_result[field1] == value1, "HGETALL should include field1 with correct value");
assert_true(hgetall_result[field2] == value2, "HGETALL should include field2 with correct value");
print(`✓ redis_hgetall(): Successfully retrieved all fields from hash ${hash_key}`);
// Test redis_hdel function
print("Testing redis_hdel()...");
let hdel_result = redis_hdel(hash_key, field1);
assert_true(hdel_result, "HDEL operation should succeed");
print(`✓ redis_hdel(): Successfully deleted field from hash ${hash_key}`);
// Verify the field was deleted
let hget_after_del = redis_hget(hash_key, field1);
assert_true(hget_after_del == "", "Field should not exist after deletion");
print("✓ Field was successfully deleted from hash");
// Test redis_list operations
print("Testing redis list operations...");
let list_key = prefix + "list";
// Push items to list
let rpush_result = redis_rpush(list_key, "item1");
assert_true(rpush_result > 0, "RPUSH operation should succeed");
redis_rpush(list_key, "item2");
redis_rpush(list_key, "item3");
print(`✓ redis_rpush(): Successfully pushed items to list ${list_key}`);
// Get list length
let llen_result = redis_llen(list_key);
assert_true(llen_result == 3, "List should have 3 items");
print(`✓ redis_llen(): List has ${llen_result} items`);
// Get list range
let lrange_result = redis_lrange(list_key, 0, -1);
assert_true(lrange_result.len() == 3, "LRANGE should return 3 items");
assert_true(lrange_result[0] == "item1", "First item should be 'item1'");
assert_true(lrange_result[2] == "item3", "Last item should be 'item3'");
print(`✓ redis_lrange(): Successfully retrieved all items from list ${list_key}`);
// Clean up
print("Cleaning up...");
redis_del(hash_key);
redis_del(list_key);
print("✓ Cleanup: All test keys removed");
print("All Redis operations tests completed successfully!");

View File

@@ -1,59 +0,0 @@
// 03_redis_authentication.rhai
// Tests for Redis client authentication (placeholder for future implementation)
// Custom assert function
fn assert_true(condition, message) {
if !condition {
print(`ASSERTION FAILED: ${message}`);
throw message;
}
}
// Helper function to check if Redis is available
fn is_redis_available() {
try {
// Try to execute a simple ping
let ping_result = redis_ping();
return ping_result == "PONG";
} catch(err) {
print(`Redis connection error: ${err}`);
return false;
}
}
print("=== Testing Redis Client Authentication ===");
// Check if Redis is available
let redis_available = is_redis_available();
if !redis_available {
print("Redis server is not available. Skipping Redis authentication tests.");
// Exit gracefully without error
return;
}
print("✓ Redis server is available");
print("Authentication support will be implemented in a future update.");
print("The backend implementation is ready, but the Rhai bindings are still in development.");
// For now, just test basic Redis functionality
print("\nTesting basic Redis functionality...");
// Test a simple operation
let test_key = "auth_test_key";
let test_value = "auth_test_value";
let set_result = redis_set(test_key, test_value);
assert_true(set_result, "Should be able to set a key");
print("✓ Set key");
let get_result = redis_get(test_key);
assert_true(get_result == test_value, "Should be able to get the key");
print("✓ Got key");
// Clean up
let del_result = redis_del(test_key);
assert_true(del_result, "Should be able to delete the key");
print("✓ Deleted test key");
print("All Redis tests completed successfully!");

View File

@@ -1,154 +0,0 @@
// run_all_tests.rhai
// Runs all Redis client module tests
print("=== Running Redis Client Module Tests ===");
// Custom assert function
fn assert_true(condition, message) {
if !condition {
print(`ASSERTION FAILED: ${message}`);
throw message;
}
}
// Helper function to check if Redis is available
fn is_redis_available() {
try {
// Try to execute a simple PING command
let ping_result = redis_ping();
return ping_result == "PONG";
} catch(err) {
print(`Redis connection error: ${err}`);
return false;
}
}
// Run each test directly
let passed = 0;
let failed = 0;
let skipped = 0;
// Check if Redis is available
let redis_available = is_redis_available();
if !redis_available {
print("Redis server is not available. Skipping all Redis tests.");
skipped = 3; // Skip all three tests
} else {
// Test 1: Redis Connection
print("\n--- Running Redis Connection Tests ---");
try {
// Test redis_ping function
print("Testing redis_ping()...");
let ping_result = redis_ping();
assert_true(ping_result == "PONG", "PING should return PONG");
print(`✓ redis_ping(): Returned ${ping_result}`);
// Test redis_set and redis_get functions
print("Testing redis_set() and redis_get()...");
let test_key = "rhai_test_key";
let test_value = "Hello from Rhai test";
// Set a value
let set_result = redis_set(test_key, test_value);
assert_true(set_result, "SET operation should succeed");
print(`✓ redis_set(): Successfully set key ${test_key}`);
// Get the value back
let get_result = redis_get(test_key);
assert_true(get_result == test_value, "GET should return the value we set");
print(`✓ redis_get(): Successfully retrieved value for key ${test_key}`);
// Clean up
redis_del(test_key);
print("--- Redis Connection Tests completed successfully ---");
passed += 1;
} catch(err) {
print(`!!! Error in Redis Connection Tests: ${err}`);
failed += 1;
}
// Test 2: Redis Operations
print("\n--- Running Redis Operations Tests ---");
try {
// Test prefix for all keys to avoid conflicts
let prefix = "rhai_test_";
// Test redis_hset and redis_hget functions
print("Testing redis_hset() and redis_hget()...");
let hash_key = prefix + "hash";
let field = "field1";
let value = "value1";
// Set hash field
let hset_result = redis_hset(hash_key, field, value);
assert_true(hset_result, "HSET operation should succeed");
print(`✓ redis_hset(): Successfully set field in hash ${hash_key}`);
// Get hash field
let hget_result = redis_hget(hash_key, field);
assert_true(hget_result == value, "HGET should return the value we set");
print(`✓ redis_hget(): Successfully retrieved value from hash ${hash_key}`);
// Clean up
redis_del(hash_key);
print("--- Redis Operations Tests completed successfully ---");
passed += 1;
} catch(err) {
print(`!!! Error in Redis Operations Tests: ${err}`);
failed += 1;
}
// Test 3: Redis Authentication
print("\n--- Running Redis Authentication Tests ---");
try {
print("Authentication support will be implemented in a future update.");
print("The backend implementation is ready, but the Rhai bindings are still in development.");
// For now, just test basic Redis functionality
print("\nTesting basic Redis functionality...");
// Test a simple operation
let test_key = "auth_test_key";
let test_value = "auth_test_value";
let set_result = redis_set(test_key, test_value);
assert_true(set_result, "Should be able to set a key");
print("✓ Set key");
let get_result = redis_get(test_key);
assert_true(get_result == test_value, "Should be able to get the key");
print("✓ Got key");
// Clean up
let del_result = redis_del(test_key);
assert_true(del_result, "Should be able to delete the key");
print("✓ Deleted test key");
print("--- Redis Authentication Tests completed successfully ---");
passed += 1;
} catch(err) {
print(`!!! Error in Redis Authentication Tests: ${err}`);
failed += 1;
}
}
print("\n=== Test Summary ===");
print(`Passed: ${passed}`);
print(`Failed: ${failed}`);
print(`Skipped: ${skipped}`);
print(`Total: ${passed + failed + skipped}`);
if failed == 0 {
if skipped > 0 {
print("\n⚠ All tests skipped or passed!");
} else {
print("\n✅ All tests passed!");
}
} else {
print("\n❌ Some tests failed!");
}
// Return the number of failed tests (0 means success)
failed;

View File

@@ -1,152 +0,0 @@
// 01_mount_operations.rhai
// Tests for RFS mount operations
// Custom assert function
fn assert_true(condition, message) {
if !condition {
print(`ASSERTION FAILED: ${message}`);
throw message;
}
}
// Custom assert_eq function
fn assert_eq(actual, expected, message) {
if actual != expected {
print(`ASSERTION FAILED: ${message}`);
print(`Expected: "${expected}"`);
print(`Actual: "${actual}"`);
throw message;
}
}
// Helper function to check if rfs is available
fn is_rfs_available() {
try {
let result = run("which rfs");
return result.success;
} catch(err) {
return false;
}
}
// Helper function to clean up mounts
fn cleanup_mounts() {
try {
rfs_unmount_all();
print("All mounts cleaned up");
} catch(err) {
print(`Error cleaning up mounts: ${err}`);
}
}
print("=== Testing RFS Mount Operations ===");
// Check if rfs is available
let rfs_available = is_rfs_available();
if !rfs_available {
print("rfs is not available. Skipping RFS tests.");
// Exit gracefully without error
return;
}
print("✓ rfs is available");
// Clean up any existing mounts
cleanup_mounts();
// Create test directories
let source_dir = "rhai_test_rfs_source";
let target_dir = "rhai_test_rfs_target";
mkdir(source_dir);
mkdir(target_dir);
// Create a test file in the source directory
let test_file = `${source_dir}/test.txt`;
file_write(test_file, "Hello from RFS test");
try {
// Test mounting a local directory
print("Testing rfs_mount() with local directory...");
let options = #{
"readonly": "true"
};
let mount = rfs_mount(source_dir, target_dir, "local", options);
// Verify mount properties
assert_true(mount.id != "", "Mount ID should not be empty");
assert_eq(mount.source, source_dir, "Mount source should match");
assert_eq(mount.target, target_dir, "Mount target should match");
assert_eq(mount.fs_type, "local", "Mount type should be local");
print(`✓ rfs_mount(): Mounted ${mount.source} to ${mount.target} with ID: ${mount.id}`);
// Test listing mounts
print("Testing rfs_list_mounts()...");
let mounts = rfs_list_mounts();
assert_true(mounts.len() > 0, "There should be at least one mount");
// Find our mount in the list
let found = false;
for m in mounts {
if m.target == target_dir {
found = true;
break;
}
}
assert_true(found, "Our mount should be in the list");
print(`✓ rfs_list_mounts(): Found ${mounts.len()} mounts`);
// Test getting mount info
print("Testing rfs_get_mount_info()...");
let mount_info = rfs_get_mount_info(target_dir);
assert_eq(mount_info.target, target_dir, "Mount info target should match");
assert_eq(mount_info.source, source_dir, "Mount info source should match");
print(`✓ rfs_get_mount_info(): Got info for mount at ${mount_info.target}`);
// Verify the mounted file is accessible
let mounted_file = `${target_dir}/test.txt`;
assert_true(exist(mounted_file), "Mounted file should exist");
let mounted_content = file_read(mounted_file);
assert_eq(mounted_content, "Hello from RFS test", "Mounted file content should match");
print("✓ Mounted file is accessible and content matches");
// Test unmounting a specific mount
print("Testing rfs_unmount()...");
rfs_unmount(target_dir);
// Verify the mount is gone
try {
rfs_get_mount_info(target_dir);
assert_true(false, "Mount should not exist after unmounting");
} catch(err) {
print("✓ rfs_unmount(): Mount successfully unmounted");
}
// Mount again to test unmount_all
print("Testing mounting again for unmount_all...");
let mount2 = rfs_mount(source_dir, target_dir, "local", options);
assert_true(mount2.id != "", "Mount ID should not be empty");
// Test unmounting all mounts
print("Testing rfs_unmount_all()...");
rfs_unmount_all();
// Verify all mounts are gone
let mounts_after = rfs_list_mounts();
assert_true(mounts_after.len() == 0, "There should be no mounts after unmount_all");
print("✓ rfs_unmount_all(): All mounts successfully unmounted");
print("All mount operations tests completed successfully!");
} catch(err) {
print(`Error: ${err}`);
// Clean up in case of error
cleanup_mounts();
throw err;
} finally {
// Clean up test directories
delete(source_dir);
delete(target_dir);
print("✓ Cleanup: Test directories removed");
}

View File

@@ -1,117 +0,0 @@
// 02_filesystem_layer_operations.rhai
// Tests for RFS filesystem layer operations
// Custom assert function
fn assert_true(condition, message) {
if !condition {
print(`ASSERTION FAILED: ${message}`);
throw message;
}
}
// Custom assert_eq function
fn assert_eq(actual, expected, message) {
if actual != expected {
print(`ASSERTION FAILED: ${message}`);
print(`Expected: "${expected}"`);
print(`Actual: "${actual}"`);
throw message;
}
}
// Helper function to check if rfs is available
fn is_rfs_available() {
try {
let result = run("which rfs");
return result.success;
} catch(err) {
return false;
}
}
print("=== Testing RFS Filesystem Layer Operations ===");
// Check if rfs is available
let rfs_available = is_rfs_available();
if !rfs_available {
print("rfs is not available. Skipping RFS tests.");
// Exit gracefully without error
return;
}
print("✓ rfs is available");
// Create test directories
let source_dir = "rhai_test_rfs_source";
let unpack_dir = "rhai_test_rfs_unpack";
mkdir(source_dir);
mkdir(unpack_dir);
// Create test files in the source directory
file_write(`${source_dir}/file1.txt`, "Content of file 1");
file_write(`${source_dir}/file2.txt`, "Content of file 2");
// Create a subdirectory with files
mkdir(`${source_dir}/subdir`);
file_write(`${source_dir}/subdir/file3.txt`, "Content of file 3");
// Output file for the filesystem layer
let output_file = "rhai_test_rfs_layer.fl";
try {
// Test packing a directory
print("Testing rfs_pack()...");
// Use a file store spec for testing
let store_specs = "file:path=.";
rfs_pack(source_dir, output_file, store_specs);
// Verify the output file exists
assert_true(exist(output_file), "Output file should exist");
print(`✓ rfs_pack(): Directory packed to ${output_file}`);
// Test listing contents of the filesystem layer
print("Testing rfs_list_contents()...");
let contents = rfs_list_contents(output_file);
// Verify the contents include our files
assert_true(contents.contains("file1.txt"), "Contents should include file1.txt");
assert_true(contents.contains("file2.txt"), "Contents should include file2.txt");
assert_true(contents.contains("subdir/file3.txt"), "Contents should include subdir/file3.txt");
print("✓ rfs_list_contents(): Layer contents listed successfully");
// Test verifying the filesystem layer
print("Testing rfs_verify()...");
let is_valid = rfs_verify(output_file);
assert_true(is_valid, "Filesystem layer should be valid");
print("✓ rfs_verify(): Layer verified successfully");
// Test unpacking the filesystem layer
print("Testing rfs_unpack()...");
rfs_unpack(output_file, unpack_dir);
// Verify the unpacked files exist and have the correct content
assert_true(exist(`${unpack_dir}/file1.txt`), "Unpacked file1.txt should exist");
assert_true(exist(`${unpack_dir}/file2.txt`), "Unpacked file2.txt should exist");
assert_true(exist(`${unpack_dir}/subdir/file3.txt`), "Unpacked subdir/file3.txt should exist");
let content1 = file_read(`${unpack_dir}/file1.txt`);
let content2 = file_read(`${unpack_dir}/file2.txt`);
let content3 = file_read(`${unpack_dir}/subdir/file3.txt`);
assert_eq(content1, "Content of file 1", "Content of file1.txt should match");
assert_eq(content2, "Content of file 2", "Content of file2.txt should match");
assert_eq(content3, "Content of file 3", "Content of file3.txt should match");
print("✓ rfs_unpack(): Layer unpacked successfully");
print("All filesystem layer operations tests completed successfully!");
} catch(err) {
print(`Error: ${err}`);
throw err;
} finally {
// Clean up test directories and files
delete(source_dir);
delete(unpack_dir);
delete(output_file);
print("✓ Cleanup: Test directories and files removed");
}

View File

@@ -1,168 +0,0 @@
// run_all_tests.rhai
// Runs all RFS module tests
print("=== Running RFS Module Tests ===");
// Custom assert function
fn assert_true(condition, message) {
if !condition {
print(`ASSERTION FAILED: ${message}`);
throw message;
}
}
// Helper function to check if rfs is available
fn is_rfs_available() {
try {
let result = run("which rfs");
return result.success;
} catch(e) {
return false;
}
}
// Helper function to clean up mounts
fn cleanup_mounts() {
try {
rfs_unmount_all();
} catch(e) {
// Ignore errors during cleanup
}
}
// Run each test directly
let passed = 0;
let failed = 0;
let skipped = 0;
let total = 0;
// Check if rfs is available
let rfs_available = is_rfs_available();
if !rfs_available {
print("rfs is not available. Skipping all RFS tests.");
skipped = 2; // Skip both tests
total = 2;
} else {
// Test 1: Mount Operations
print("\n--- Running Mount Operations Tests ---");
try {
// Clean up any existing mounts
cleanup_mounts();
// Create test directories
let source_dir = "rhai_test_rfs_source";
let target_dir = "rhai_test_rfs_target";
mkdir(source_dir);
mkdir(target_dir);
// Create a test file in the source directory
let test_file = `${source_dir}/test.txt`;
file_write(test_file, "Hello from RFS test");
// Mount the directory
let options = #{
"readonly": "true"
};
let mount = rfs_mount(source_dir, target_dir, "local", options);
assert_true(mount.id != "", "Mount ID should not be empty");
// List mounts
let mounts = rfs_list_mounts();
assert_true(mounts.len() > 0, "There should be at least one mount");
// Unmount
rfs_unmount(target_dir);
// Clean up
delete(source_dir);
delete(target_dir);
print("--- Mount Operations Tests completed successfully ---");
passed += 1;
} catch(err) {
print(`!!! Error in Mount Operations Tests: ${err}`);
failed += 1;
// Clean up in case of error
cleanup_mounts();
try {
delete("rhai_test_rfs_source");
delete("rhai_test_rfs_target");
} catch(e) {
// Ignore errors during cleanup
}
}
total += 1;
// Test 2: Filesystem Layer Operations
print("\n--- Running Filesystem Layer Operations Tests ---");
try {
// Create test directories
let source_dir = "rhai_test_rfs_source";
let unpack_dir = "rhai_test_rfs_unpack";
mkdir(source_dir);
mkdir(unpack_dir);
// Create test files in the source directory
file_write(`${source_dir}/file1.txt`, "Content of file 1");
// Output file for the filesystem layer
let output_file = "rhai_test_rfs_layer.fl";
// Pack the directory
let store_specs = "file:path=.";
rfs_pack(source_dir, output_file, store_specs);
// List contents
let contents = rfs_list_contents(output_file);
assert_true(contents.contains("file1.txt"), "Contents should include file1.txt");
// Verify the layer
let is_valid = rfs_verify(output_file);
assert_true(is_valid, "Filesystem layer should be valid");
// Unpack the layer
rfs_unpack(output_file, unpack_dir);
// Clean up
delete(source_dir);
delete(unpack_dir);
delete(output_file);
print("--- Filesystem Layer Operations Tests completed successfully ---");
passed += 1;
} catch(err) {
print(`!!! Error in Filesystem Layer Operations Tests: ${err}`);
failed += 1;
// Clean up in case of error
try {
delete("rhai_test_rfs_source");
delete("rhai_test_rfs_unpack");
delete("rhai_test_rfs_layer.fl");
} catch(e) {
// Ignore errors during cleanup
}
}
total += 1;
}
print("\n=== Test Summary ===");
print(`Passed: ${passed}`);
print(`Failed: ${failed}`);
print(`Skipped: ${skipped}`);
print(`Total: ${total}`);
if failed == 0 {
if skipped > 0 {
print("\n⚠ All tests skipped or passed!");
} else {
print("\n✅ All tests passed!");
}
} else {
print("\n❌ Some tests failed!");
}
// Return the number of failed tests (0 means success)
failed;

View File

@@ -1,95 +0,0 @@
#!/bin/bash
# Run all Rhai tests
# This script runs all the Rhai tests in the rhai_tests directory
# Set the base directory
BASE_DIR="src/rhai_tests"
# Define colors for output
GREEN='\033[0;32m'
RED='\033[0;31m'
YELLOW='\033[0;33m'
NC='\033[0m' # No Color
# Initialize counters
TOTAL_MODULES=0
PASSED_MODULES=0
FAILED_MODULES=0
# Function to run tests in a directory
run_tests_in_dir() {
local dir=$1
local module_name=$(basename $dir)
echo -e "${YELLOW}Running tests for module: ${module_name}${NC}"
# Check if the directory has a run_all_tests.rhai script
if [ -f "${dir}/run_all_tests.rhai" ]; then
echo "Using module's run_all_tests.rhai script"
herodo --path "${dir}/run_all_tests.rhai"
if [ $? -eq 0 ]; then
echo -e "${GREEN}✓ All tests passed for module: ${module_name}${NC}"
PASSED_MODULES=$((PASSED_MODULES + 1))
else
echo -e "${RED}✗ Tests failed for module: ${module_name}${NC}"
FAILED_MODULES=$((FAILED_MODULES + 1))
fi
else
# Run all .rhai files in the directory
local test_files=$(find "${dir}" -name "*.rhai" | sort)
local all_passed=true
for test_file in $test_files; do
echo "Running test: $(basename $test_file)"
herodo --path "$test_file"
if [ $? -ne 0 ]; then
all_passed=false
fi
done
if $all_passed; then
echo -e "${GREEN}✓ All tests passed for module: ${module_name}${NC}"
PASSED_MODULES=$((PASSED_MODULES + 1))
else
echo -e "${RED}✗ Tests failed for module: ${module_name}${NC}"
FAILED_MODULES=$((FAILED_MODULES + 1))
fi
fi
TOTAL_MODULES=$((TOTAL_MODULES + 1))
echo ""
}
# Main function
main() {
echo "=======================================
Running Rhai Tests
======================================="
# Find all module directories
for dir in $(find "${BASE_DIR}" -mindepth 1 -maxdepth 1 -type d | sort); do
run_tests_in_dir "$dir"
done
# Print summary
echo "=======================================
Test Summary
======================================="
echo "Total modules tested: ${TOTAL_MODULES}"
echo "Passed: ${PASSED_MODULES}"
echo "Failed: ${FAILED_MODULES}"
if [ $FAILED_MODULES -gt 0 ]; then
echo -e "${RED}Some tests failed!${NC}"
exit 1
else
echo -e "${GREEN}All tests passed!${NC}"
exit 0
fi
}
# Run the main function
main

View File

@@ -1,108 +0,0 @@
// 01_text_indentation.rhai
// Tests for text indentation functions in the Text module
// Custom assert function
fn assert_true(condition, message) {
if !condition {
print(`ASSERTION FAILED: ${message}`);
throw message;
}
}
// Custom assert_eq function
fn assert_eq(actual, expected, message) {
if actual != expected {
print(`ASSERTION FAILED: ${message}`);
print(`Expected: "${expected}"`);
print(`Actual: "${actual}"`);
throw message;
}
}
print("=== Testing Text Indentation Functions ===");
// Test dedent function
print("Testing dedent()...");
// Test case 1: Basic indentation
let indented_text1 = " line 1\n line 2\n line 3";
let expected_dedented1 = "line 1\nline 2\n line 3";
let dedented1 = dedent(indented_text1);
assert_eq(dedented1, expected_dedented1, "Basic indentation should be removed correctly");
print("✓ dedent(): Basic indentation removed correctly");
// Test case 2: Mixed indentation
let indented_text2 = " line 1\n line 2\n line 3";
let expected_dedented2 = "line 1\n line 2\nline 3";
let dedented2 = dedent(indented_text2);
assert_eq(dedented2, expected_dedented2, "Mixed indentation should be handled correctly");
print("✓ dedent(): Mixed indentation handled correctly");
// Test case 3: Empty lines
let indented_text3 = " line 1\n\n line 3";
let expected_dedented3 = "line 1\n\nline 3";
let dedented3 = dedent(indented_text3);
assert_eq(dedented3, expected_dedented3, "Empty lines should be preserved");
print("✓ dedent(): Empty lines preserved correctly");
// Test case 4: No indentation
let text4 = "line 1\nline 2\nline 3";
let dedented4 = dedent(text4);
assert_eq(dedented4, text4, "Text without indentation should remain unchanged");
print("✓ dedent(): Text without indentation remains unchanged");
// Test case 5: Single line
let indented_text5 = " single line";
let expected_dedented5 = "single line";
let dedented5 = dedent(indented_text5);
assert_eq(dedented5, expected_dedented5, "Single line indentation should be removed");
print("✓ dedent(): Single line indentation removed correctly");
// Test prefix function
print("\nTesting prefix()...");
// Test case 1: Basic prefix
let text1 = "line 1\nline 2\nline 3";
let expected_prefixed1 = " line 1\n line 2\n line 3";
let prefixed1 = prefix(text1, " ");
assert_eq(prefixed1, expected_prefixed1, "Basic prefix should be added correctly");
print("✓ prefix(): Basic prefix added correctly");
// Test case 2: Empty prefix
let text2 = "line 1\nline 2\nline 3";
let prefixed2 = prefix(text2, "");
assert_eq(prefixed2, text2, "Empty prefix should not change the text");
print("✓ prefix(): Empty prefix doesn't change the text");
// Test case 3: Prefix with empty lines
let text3 = "line 1\n\nline 3";
let expected_prefixed3 = " line 1\n \n line 3";
let prefixed3 = prefix(text3, " ");
assert_eq(prefixed3, expected_prefixed3, "Prefix should be added to empty lines");
print("✓ prefix(): Prefix added to empty lines correctly");
// Test case 4: Single line
let text4 = "single line";
let expected_prefixed4 = " single line";
let prefixed4 = prefix(text4, " ");
assert_eq(prefixed4, expected_prefixed4, "Prefix should be added to single line");
print("✓ prefix(): Prefix added to single line correctly");
// Test case 5: Non-space prefix
let text5 = "line 1\nline 2\nline 3";
let expected_prefixed5 = ">>> line 1\n>>> line 2\n>>> line 3";
let prefixed5 = prefix(text5, ">>> ");
assert_eq(prefixed5, expected_prefixed5, "Non-space prefix should be added correctly");
print("✓ prefix(): Non-space prefix added correctly");
// Test combining dedent and prefix
print("\nTesting combination of dedent() and prefix()...");
let indented_text = " line 1\n line 2\n line 3";
let dedented = dedent(indented_text);
let prefixed = prefix(dedented, " ");
let expected_result = " line 1\n line 2\n line 3";
assert_eq(prefixed, expected_result, "Combination of dedent and prefix should work correctly");
print("✓ dedent() + prefix(): Combination works correctly");
print("\nAll text indentation tests completed successfully!");

View File

@@ -1,100 +0,0 @@
// 02_name_path_fix.rhai
// Tests for filename and path normalization functions in the Text module
// Custom assert function
fn assert_true(condition, message) {
if !condition {
print(`ASSERTION FAILED: ${message}`);
throw message;
}
}
// Custom assert_eq function
fn assert_eq(actual, expected, message) {
if actual != expected {
print(`ASSERTION FAILED: ${message}`);
print(`Expected: "${expected}"`);
print(`Actual: "${actual}"`);
throw message;
}
}
print("=== Testing Filename and Path Normalization Functions ===");
// Test name_fix function
print("Testing name_fix()...");
// Test case 1: Basic name fixing
let name1 = "Hello World";
let expected_fixed1 = "hello_world";
let fixed1 = name_fix(name1);
assert_eq(fixed1, expected_fixed1, "Spaces should be replaced with underscores and converted to lowercase");
print("✓ name_fix(): Basic name fixing works correctly");
// Test case 2: Special characters
let name2 = "File-Name.txt";
let expected_fixed2 = "file_name.txt";
let fixed2 = name_fix(name2);
assert_eq(fixed2, expected_fixed2, "Hyphens should be replaced with underscores");
print("✓ name_fix(): Special characters handled correctly");
// Test case 3: Multiple special characters
let name3 = "Test!@#$%^&*()";
let expected_fixed3 = "test_";
let fixed3 = name_fix(name3);
assert_eq(fixed3, expected_fixed3, "Multiple special characters should be collapsed into a single underscore");
print("✓ name_fix(): Multiple special characters handled correctly");
// Test case 4: Non-ASCII characters
let name4 = "Café";
let expected_fixed4 = "caf";
let fixed4 = name_fix(name4);
assert_eq(fixed4, expected_fixed4, "Non-ASCII characters should be removed");
print("✓ name_fix(): Non-ASCII characters removed correctly");
// Test case 5: Uppercase conversion
let name5 = "UPPERCASE";
let expected_fixed5 = "uppercase";
let fixed5 = name_fix(name5);
assert_eq(fixed5, expected_fixed5, "Uppercase should be converted to lowercase");
print("✓ name_fix(): Uppercase conversion works correctly");
// Test path_fix function
print("\nTesting path_fix()...");
// Test case 1: Path ending with /
let path1 = "/path/to/directory/";
let expected_fixed_path1 = "/path/to/directory/";
let fixed_path1 = path_fix(path1);
assert_eq(fixed_path1, expected_fixed_path1, "Path ending with / should remain unchanged");
print("✓ path_fix(): Path ending with / remains unchanged");
// Test case 2: Single filename
let path2 = "filename.txt";
let expected_fixed_path2 = "filename.txt";
let fixed_path2 = path_fix(path2);
assert_eq(fixed_path2, expected_fixed_path2, "Single filename should be fixed");
print("✓ path_fix(): Single filename fixed correctly");
// Test case 3: Path with filename
let path3 = "/path/to/File Name.txt";
let expected_fixed_path3 = "/path/to/file_name.txt";
let fixed_path3 = path_fix(path3);
assert_eq(fixed_path3, expected_fixed_path3, "Only the filename part of the path should be fixed");
print("✓ path_fix(): Path with filename fixed correctly");
// Test case 4: Relative path
let path4 = "./relative/path/to/DOCUMENT-123.pdf";
let expected_fixed_path4 = "./relative/path/to/document_123.pdf";
let fixed_path4 = path_fix(path4);
assert_eq(fixed_path4, expected_fixed_path4, "Relative path should be handled correctly");
print("✓ path_fix(): Relative path handled correctly");
// Test case 5: Path with special characters in filename
let path5 = "/path/with/[special]<chars>.txt";
let expected_fixed_path5 = "/path/with/_special_chars_.txt";
let fixed_path5 = path_fix(path5);
assert_eq(fixed_path5, expected_fixed_path5, "Special characters in filename should be handled correctly");
print("✓ path_fix(): Path with special characters in filename handled correctly");
print("\nAll filename and path normalization tests completed successfully!");

View File

@@ -1,134 +0,0 @@
// 03_text_replacer.rhai
// Tests for text replacement functions in the Text module
// Custom assert function
fn assert_true(condition, message) {
if !condition {
print(`ASSERTION FAILED: ${message}`);
throw message;
}
}
// Custom assert_eq function
fn assert_eq(actual, expected, message) {
if actual != expected {
print(`ASSERTION FAILED: ${message}`);
print(`Expected: "${expected}"`);
print(`Actual: "${actual}"`);
throw message;
}
}
print("=== Testing Text Replacement Functions ===");
// Test TextReplacer with simple replacements
print("Testing TextReplacer with simple replacements...");
// Test case 1: Basic replacement
let replacer1 = text_replacer_new()
.pattern("foo")
.replacement("bar")
.build();
let input1 = "foo bar foo";
let expected_output1 = "bar bar bar";
let output1 = replacer1.replace(input1);
assert_eq(output1, expected_output1, "Basic replacement should work correctly");
print("✓ TextReplacer: Basic replacement works correctly");
// Test case 2: Multiple replacements
let replacer2 = text_replacer_new()
.pattern("foo")
.replacement("bar")
.and()
.pattern("baz")
.replacement("qux")
.build();
let input2 = "foo baz foo";
let expected_output2 = "bar qux bar";
let output2 = replacer2.replace(input2);
assert_eq(output2, expected_output2, "Multiple replacements should work correctly");
print("✓ TextReplacer: Multiple replacements work correctly");
// Test TextReplacer with regex replacements
print("\nTesting TextReplacer with regex replacements...");
// Test case 3: Basic regex replacement
let replacer3 = text_replacer_new()
.pattern("f.o")
.replacement("bar")
.regex(true)
.build();
let input3 = "foo fao fio";
let output3 = replacer3.replace(input3);
// The regex "f.o" matches "foo", "fao", and "fio"
let expected_output3 = "bar bar bar";
assert_eq(output3, expected_output3, "Basic regex replacement should work correctly");
print("✓ TextReplacer: Basic regex replacement works correctly");
// Test case 4: Case-insensitive regex replacement
let replacer4 = text_replacer_new()
.pattern("foo")
.replacement("bar")
.regex(true)
.case_insensitive(true)
.build();
let input4 = "FOO foo Foo";
let expected_output4 = "bar bar bar";
let output4 = replacer4.replace(input4);
assert_eq(output4, expected_output4, "Case-insensitive regex replacement should work correctly");
print("✓ TextReplacer: Case-insensitive regex replacement works correctly");
// Test TextReplacer with file operations
print("\nTesting TextReplacer with file operations...");
// Create a temporary file for testing
let test_dir = "rhai_test_text_replacer";
mkdir(test_dir);
let test_file = `${test_dir}/test_file.txt`;
let test_output_file = `${test_dir}/test_output_file.txt`;
// Write test content to the file
let test_content = "This is a test file with foo and bar.";
file_write(test_file, test_content);
// Test case 5: Replace in file and get result as string
let replacer5 = text_replacer_new()
.pattern("foo")
.replacement("baz")
.build();
let expected_output5 = "This is a test file with baz and bar.";
let output5 = replacer5.replace_file(test_file);
assert_eq(output5, expected_output5, "replace_file should return the replaced content");
print("✓ TextReplacer: replace_file works correctly");
// Test case 6: Replace in file and write to a new file
replacer5.replace_file_to(test_file, test_output_file);
let output_content = file_read(test_output_file);
assert_eq(output_content, expected_output5, "replace_file_to should write the replaced content to a new file");
print("✓ TextReplacer: replace_file_to works correctly");
// Test case 7: Replace in file and write back to the same file
// First, update the test file with the replaced content
file_write(test_file, expected_output5);
let replacer6 = text_replacer_new()
.pattern("baz")
.replacement("qux")
.build();
replacer6.replace_file_in_place(test_file);
let updated_content = file_read(test_file);
let expected_output6 = "This is a test file with qux and bar.";
assert_eq(updated_content, expected_output6, "replace_file_in_place should update the file in place");
print("✓ TextReplacer: replace_file_in_place works correctly");
// Clean up
delete(test_dir);
print("✓ Cleanup: Test directory removed");
print("\nAll text replacement tests completed successfully!");

View File

@@ -1,102 +0,0 @@
// 04_template_builder.rhai
// Tests for template rendering functions in the Text module
// Custom assert function
fn assert_true(condition, message) {
if !condition {
print(`ASSERTION FAILED: ${message}`);
throw message;
}
}
// Custom assert_eq function
fn assert_eq(actual, expected, message) {
if actual != expected {
print(`ASSERTION FAILED: ${message}`);
print(`Expected: "${expected}"`);
print(`Actual: "${actual}"`);
throw message;
}
}
print("=== Testing Template Rendering Functions ===");
// Create a temporary directory for testing
let test_dir = "rhai_test_template";
mkdir(test_dir);
// Test TemplateBuilder with string template
print("Testing TemplateBuilder with string template...");
// Test case 1: Basic template with string variable
let template1 = "Hello, {{ name }}!";
let builder1 = template_builder_open(template1);
builder1.add_var("name", "World");
let expected_output1 = "Hello, World!";
let output1 = builder1.render();
assert_eq(output1, expected_output1, "Basic template with string variable should render correctly");
print("✓ TemplateBuilder: Basic template with string variable renders correctly");
// Test case 2: Template with multiple variables of different types
let template2 = "{{ name }} is {{ age }} years old and {{ is_active ? 'active' : 'inactive' }}.";
let builder2 = template_builder_open(template2);
builder2.add_var("name", "John");
builder2.add_var("age", 30);
builder2.add_var("is_active", true);
let expected_output2 = "John is 30 years old and active.";
let output2 = builder2.render();
assert_eq(output2, expected_output2, "Template with multiple variables should render correctly");
print("✓ TemplateBuilder: Template with multiple variables renders correctly");
// Test case 3: Template with array variable
let template3 = "Items: {% for item in items %}{{ item }}{% if !loop.last %}, {% endif %}{% endfor %}";
let builder3 = template_builder_open(template3);
let items = ["apple", "banana", "cherry"];
builder3.add_var("items", items);
let expected_output3 = "Items: apple, banana, cherry";
let output3 = builder3.render();
assert_eq(output3, expected_output3, "Template with array variable should render correctly");
print("✓ TemplateBuilder: Template with array variable renders correctly");
// Test case 4: Template with map variable
let template4 = "User: {{ user.name }}, Age: {{ user.age }}";
let builder4 = template_builder_open(template4);
let user = #{
name: "Alice",
age: 25
};
builder4.add_vars(user);
let expected_output4 = "User: Alice, Age: 25";
let output4 = builder4.render();
assert_eq(output4, expected_output4, "Template with map variable should render correctly");
print("✓ TemplateBuilder: Template with map variable renders correctly");
// Test TemplateBuilder with file operations
print("\nTesting TemplateBuilder with file operations...");
// Create a template file
let template_file = `${test_dir}/template.txt`;
let template_content = "Hello, {{ name }}! You are {{ age }} years old.";
file_write(template_file, template_content);
// Test case 5: Template from file
let builder5 = template_builder_open(template_file);
builder5.add_var("name", "Bob");
builder5.add_var("age", 40);
let expected_output5 = "Hello, Bob! You are 40 years old.";
let output5 = builder5.render();
assert_eq(output5, expected_output5, "Template from file should render correctly");
print("✓ TemplateBuilder: Template from file renders correctly");
// Test case 6: Render to file
let output_file = `${test_dir}/output.txt`;
builder5.render_to_file(output_file);
let output_content = file_read(output_file);
assert_eq(output_content, expected_output5, "render_to_file should write the rendered content to a file");
print("✓ TemplateBuilder: render_to_file works correctly");
// Clean up
delete(test_dir);
print("✓ Cleanup: Test directory removed");
print("\nAll template rendering tests completed successfully!");

View File

@@ -1,138 +0,0 @@
// run_all_tests.rhai
// Runs all Text module tests
print("=== Running Text Module Tests ===");
// Custom assert function
fn assert_true(condition, message) {
if !condition {
print(`ASSERTION FAILED: ${message}`);
throw message;
}
}
// Custom assert_eq function
fn assert_eq(actual, expected, message) {
if actual != expected {
print(`ASSERTION FAILED: ${message}`);
print(`Expected: "${expected}"`);
print(`Actual: "${actual}"`);
throw message;
}
}
// Run each test directly
let passed = 0;
let failed = 0;
let total = 0;
// Test 1: Text Indentation
print("\n--- Running Text Indentation Tests ---");
try {
// Test dedent function
print("Testing dedent()...");
let indented_text = " line 1\n line 2\n line 3";
let dedented = dedent(indented_text);
assert_eq(dedented, "line 1\nline 2\n line 3", "Basic indentation should be removed correctly");
print("✓ dedent(): Basic indentation removed correctly");
// Test prefix function
print("Testing prefix()...");
let text = "line 1\nline 2\nline 3";
let prefixed = prefix(text, " ");
assert_eq(prefixed, " line 1\n line 2\n line 3", "Basic prefix should be added correctly");
print("✓ prefix(): Basic prefix added correctly");
print("--- Text Indentation Tests completed successfully ---");
passed += 1;
} catch(err) {
print(`!!! Error in Text Indentation Tests: ${err}`);
failed += 1;
}
total += 1;
// Test 2: Filename and Path Normalization
print("\n--- Running Filename and Path Normalization Tests ---");
try {
// Test name_fix function
print("Testing name_fix()...");
let name = "Hello World";
let fixed_name = name_fix(name);
assert_eq(fixed_name, "hello_world", "Spaces should be replaced with underscores and converted to lowercase");
print("✓ name_fix(): Basic name fixing works correctly");
// Test path_fix function
print("Testing path_fix()...");
let path = "/path/to/File Name.txt";
let fixed_path = path_fix(path);
assert_eq(fixed_path, "/path/to/file_name.txt", "Only the filename part of the path should be fixed");
print("✓ path_fix(): Path with filename fixed correctly");
print("--- Filename and Path Normalization Tests completed successfully ---");
passed += 1;
} catch(err) {
print(`!!! Error in Filename and Path Normalization Tests: ${err}`);
failed += 1;
}
total += 1;
// Test 3: Text Replacement
print("\n--- Running Text Replacement Tests ---");
try {
// Test TextReplacer with simple replacements
print("Testing TextReplacer with simple replacements...");
let replacer = text_replacer_new()
.pattern("foo")
.replacement("bar")
.build();
let input = "foo bar foo";
let output = replacer.replace(input);
assert_eq(output, "bar bar bar", "Basic replacement should work correctly");
print("✓ TextReplacer: Basic replacement works correctly");
// Create a temporary file for testing
let test_dir = "rhai_test_text_replacer";
mkdir(test_dir);
let test_file = `${test_dir}/test_file.txt`;
// Write test content to the file
let test_content = "This is a test file with foo and bar.";
file_write(test_file, test_content);
// Test replace_file
let expected_output = "This is a test file with bar and bar.";
let output = replacer.replace_file(test_file);
assert_eq(output, expected_output, "replace_file should return the replaced content");
print("✓ TextReplacer: replace_file works correctly");
// Clean up
delete(test_dir);
print("✓ Cleanup: Test directory removed");
print("--- Text Replacement Tests completed successfully ---");
passed += 1;
} catch(err) {
print(`!!! Error in Text Replacement Tests: ${err}`);
failed += 1;
}
total += 1;
// Skip Template Rendering Tests for now
print("\n--- Skipping Template Rendering Tests ---");
print("Template rendering tests are skipped due to compatibility issues.");
total += 1;
print("\n=== Test Summary ===");
print(`Passed: ${passed}`);
print(`Failed: ${failed}`);
print(`Total: ${total}`);
if failed == 0 {
print("\n✅ All tests passed!");
} else {
print("\n❌ Some tests failed!");
}
// Return the number of failed tests (0 means success)
failed;