diff --git a/example/wasm-key-encode/index.html b/example/wasm-key-encode/index.html
index 714988b4d..9f4d8bebb 100644
--- a/example/wasm-key-encode/index.html
+++ b/example/wasm-key-encode/index.html
@@ -458,7 +458,7 @@
// Set UTF-8 text from the key event (the actual character produced)
if (event.key.length === 1) {
const utf8Bytes = new TextEncoder().encode(event.key);
- const utf8Ptr = wasmInstance.exports.ghostty_wasm_alloc_buffer(utf8Bytes.length);
+ const utf8Ptr = wasmInstance.exports.ghostty_wasm_alloc_u8_array(utf8Bytes.length);
new Uint8Array(getBuffer()).set(utf8Bytes, utf8Ptr);
wasmInstance.exports.ghostty_key_event_set_utf8(eventPtr, utf8Ptr, utf8Bytes.length);
}
@@ -477,7 +477,7 @@
const required = new DataView(getBuffer()).getUint32(requiredPtr, true);
- const bufPtr = wasmInstance.exports.ghostty_wasm_alloc_buffer(required);
+ const bufPtr = wasmInstance.exports.ghostty_wasm_alloc_u8_array(required);
const writtenPtr = wasmInstance.exports.ghostty_wasm_alloc_usize();
const encodeResult = wasmInstance.exports.ghostty_key_encoder_encode(
encoderPtr, eventPtr, bufPtr, required, writtenPtr
diff --git a/example/wasm-sgr/README.md b/example/wasm-sgr/README.md
new file mode 100644
index 000000000..a107c910d
--- /dev/null
+++ b/example/wasm-sgr/README.md
@@ -0,0 +1,39 @@
+# WebAssembly SGR Parser Example
+
+This example demonstrates how to use the Ghostty VT library from WebAssembly
+to parse terminal SGR (Select Graphic Rendition) sequences and extract text
+styling attributes.
+
+## Building
+
+First, build the WebAssembly module:
+
+```bash
+zig build lib-vt -Dtarget=wasm32-freestanding -Doptimize=ReleaseSmall
+```
+
+This will create `zig-out/bin/ghostty-vt.wasm`.
+
+## Running
+
+**Important:** You must serve this via HTTP, not open it as a file directly.
+Browsers block loading WASM files from `file://` URLs.
+
+From the **root of the ghostty repository**, serve with a local HTTP server:
+
+```bash
+# Using Python (recommended)
+python3 -m http.server 8000
+
+# Or using Node.js
+npx serve .
+
+# Or using PHP
+php -S localhost:8000
+```
+
+Then open your browser to:
+
+```
+http://localhost:8000/example/wasm-sgr/
+```
diff --git a/example/wasm-sgr/index.html b/example/wasm-sgr/index.html
new file mode 100644
index 000000000..e62b26c7e
--- /dev/null
+++ b/example/wasm-sgr/index.html
@@ -0,0 +1,457 @@
+
+
+
+
+
+ Ghostty VT SGR Parser - WebAssembly Example
+
+
+
+ Ghostty VT SGR Parser - WebAssembly Example
+ This example demonstrates parsing terminal SGR (Select Graphic Rendition) sequences using the Ghostty VT WebAssembly module.
+
+ Loading WebAssembly module...
+
+
+
+ Waiting for input...
+
+ Note: This example must be served via HTTP (not opened directly as a file). See the README for instructions.
+
+
+
+
diff --git a/include/ghostty/vt/color.h b/include/ghostty/vt/color.h
index 9e7fe6f4d..0d57b8db4 100644
--- a/include/ghostty/vt/color.h
+++ b/include/ghostty/vt/color.h
@@ -70,6 +70,25 @@ typedef uint8_t GhosttyColorPaletteIndex;
/** @} */
+/**
+ * Get the RGB color components.
+ *
+ * This function extracts the individual red, green, and blue components
+ * from a GhosttyColorRgb value. Primarily useful in WebAssembly environments
+ * where accessing struct fields directly is difficult.
+ *
+ * @param color The RGB color value
+ * @param r Pointer to store the red component (0-255)
+ * @param g Pointer to store the green component (0-255)
+ * @param b Pointer to store the blue component (0-255)
+ *
+ * @ingroup sgr
+ */
+void ghostty_color_rgb_get(GhosttyColorRgb color,
+ uint8_t* r,
+ uint8_t* g,
+ uint8_t* b);
+
#ifdef __cplusplus
}
#endif
diff --git a/include/ghostty/vt/sgr.h b/include/ghostty/vt/sgr.h
index a296a280a..0c1afc309 100644
--- a/include/ghostty/vt/sgr.h
+++ b/include/ghostty/vt/sgr.h
@@ -18,9 +18,9 @@
*
* The parser processes SGR parameters from CSI sequences (e.g., `ESC[1;31m`)
* and returns individual text attributes like bold, italic, colors, etc.
- * It supports both semicolon (`;`) and colon (`:`) separators, possibly mixed,
- * and handles various color formats including 8-color, 16-color, 256-color,
- * X11 named colors, and RGB in multiple formats.
+ * It supports both semicolon (`;`) and colon (`:`) separators, possibly mixed,
+ * and handles various color formats including 8-color, 16-color, 256-color,
+ * X11 named colors, and RGB in multiple formats.
*
* ## Basic Usage
*
@@ -35,18 +35,18 @@
* #include
* #include
* #include
- *
+ *
* int main() {
* // Create parser
* GhosttySgrParser parser;
* GhosttyResult result = ghostty_sgr_new(NULL, &parser);
* assert(result == GHOSTTY_SUCCESS);
- *
+ *
* // Parse "bold, red foreground" sequence: ESC[1;31m
* uint16_t params[] = {1, 31};
* result = ghostty_sgr_set_params(parser, params, NULL, 2);
* assert(result == GHOSTTY_SUCCESS);
- *
+ *
* // Iterate through attributes
* GhosttySgrAttribute attr;
* while (ghostty_sgr_next(parser, &attr)) {
@@ -61,7 +61,7 @@
* break;
* }
* }
- *
+ *
* // Cleanup
* ghostty_sgr_free(parser);
* return 0;
@@ -71,12 +71,12 @@
* @{
*/
+#include
+#include
+#include
#include
#include
#include
-#include
-#include
-#include
#ifdef __cplusplus
extern "C" {
@@ -84,13 +84,13 @@ extern "C" {
/**
* Opaque handle to an SGR parser instance.
- *
+ *
* This handle represents an SGR (Select Graphic Rendition) parser that can
* be used to parse SGR sequences and extract individual text attributes.
*
* @ingroup sgr
*/
-typedef struct GhosttySgrParser *GhosttySgrParser;
+typedef struct GhosttySgrParser* GhosttySgrParser;
/**
* SGR attribute tags.
@@ -158,9 +158,9 @@ typedef enum {
* @ingroup sgr
*/
typedef struct {
- const uint16_t *full_ptr;
+ const uint16_t* full_ptr;
size_t full_len;
- const uint16_t *partial_ptr;
+ const uint16_t* partial_ptr;
size_t partial_len;
} GhosttySgrUnknown;
@@ -196,7 +196,7 @@ typedef union {
* Always check the tag field to determine which value union member is valid.
*
* Attributes without associated data (e.g., GHOSTTY_SGR_ATTR_BOLD) can be
- * identified by tag alone; the value union is not used for these and
+ * identified by tag alone; the value union is not used for these and
* the memory in the value field is undefined.
*
* @ingroup sgr
@@ -208,94 +208,182 @@ typedef struct {
/**
* Create a new SGR parser instance.
- *
+ *
* Creates a new SGR (Select Graphic Rendition) parser using the provided
* allocator. The parser must be freed using ghostty_sgr_free() when
* no longer needed.
- *
- * @param allocator Pointer to the allocator to use for memory management, or NULL to use the default allocator
+ *
+ * @param allocator Pointer to the allocator to use for memory management, or
+ * NULL to use the default allocator
* @param parser Pointer to store the created parser handle
* @return GHOSTTY_SUCCESS on success, or an error code on failure
- *
+ *
* @ingroup sgr
*/
-GhosttyResult ghostty_sgr_new(const GhosttyAllocator *allocator, GhosttySgrParser *parser);
+GhosttyResult ghostty_sgr_new(const GhosttyAllocator* allocator,
+ GhosttySgrParser* parser);
/**
* Free an SGR parser instance.
- *
+ *
* Releases all resources associated with the SGR parser. After this call,
* the parser handle becomes invalid and must not be used. This includes
* any attributes previously returned by ghostty_sgr_next().
- *
+ *
* @param parser The parser handle to free (may be NULL)
- *
+ *
* @ingroup sgr
*/
void ghostty_sgr_free(GhosttySgrParser parser);
/**
* Reset an SGR parser instance to the beginning of the parameter list.
- *
+ *
* Resets the parser's iteration state without clearing the parameters.
* After calling this, ghostty_sgr_next() will start from the beginning
* of the parameter list again.
- *
+ *
* @param parser The parser handle to reset, must not be NULL
- *
+ *
* @ingroup sgr
*/
void ghostty_sgr_reset(GhosttySgrParser parser);
/**
* Set SGR parameters for parsing.
- *
+ *
* Sets the SGR parameter list to parse. Parameters are the numeric values
* from a CSI SGR sequence (e.g., for `ESC[1;31m`, params would be {1, 31}).
- *
+ *
* The separators array optionally specifies the separator type for each
* parameter position. Each byte should be either ';' for semicolon or ':'
* for colon. This is needed for certain color formats that use colon
* separators (e.g., `ESC[4:3m` for curly underline). Any invalid separator
- * values are treated as semicolons. The separators array must have the same
+ * values are treated as semicolons. The separators array must have the same
* length as the params array, if it is not NULL.
- *
+ *
* If separators is NULL, all parameters are assumed to be semicolon-separated.
- *
+ *
* This function makes an internal copy of the parameter and separator data,
* so the caller can safely free or modify the input arrays after this call.
- *
+ *
* After calling this function, the parser is automatically reset and ready
* to iterate from the beginning.
- *
+ *
* @param parser The parser handle, must not be NULL
* @param params Array of SGR parameter values
- * @param separators Optional array of separator characters (';' or ':'), or NULL
+ * @param separators Optional array of separator characters (';' or ':'), or
+ * NULL
* @param len Number of parameters (and separators if provided)
* @return GHOSTTY_SUCCESS on success, or an error code on failure
- *
+ *
* @ingroup sgr
*/
-GhosttyResult ghostty_sgr_set_params(
- GhosttySgrParser parser,
- const uint16_t *params,
- const char *separators,
- size_t len);
+GhosttyResult ghostty_sgr_set_params(GhosttySgrParser parser,
+ const uint16_t* params,
+ const char* separators,
+ size_t len);
/**
* Get the next SGR attribute.
- *
+ *
* Parses and returns the next attribute from the parameter list.
* Call this function repeatedly until it returns false to process
* all attributes in the sequence.
- *
+ *
* @param parser The parser handle, must not be NULL
* @param attr Pointer to store the next attribute
* @return true if an attribute was returned, false if no more attributes
- *
+ *
* @ingroup sgr
*/
-bool ghostty_sgr_next(GhosttySgrParser parser, GhosttySgrAttribute *attr);
+bool ghostty_sgr_next(GhosttySgrParser parser, GhosttySgrAttribute* attr);
+
+/**
+ * Get the full parameter list from an unknown SGR attribute.
+ *
+ * This function retrieves the full parameter list that was provided to the
+ * parser when an unknown attribute was encountered. Primarily useful in
+ * WebAssembly environments where accessing struct fields directly is difficult.
+ *
+ * @param unknown The unknown attribute data
+ * @param ptr Pointer to store the pointer to the parameter array (may be NULL)
+ * @return The length of the full parameter array
+ *
+ * @ingroup sgr
+ */
+size_t ghostty_sgr_unknown_full(GhosttySgrUnknown unknown,
+ const uint16_t** ptr);
+
+/**
+ * Get the partial parameter list from an unknown SGR attribute.
+ *
+ * This function retrieves the partial parameter list where parsing stopped
+ * when an unknown attribute was encountered. Primarily useful in WebAssembly
+ * environments where accessing struct fields directly is difficult.
+ *
+ * @param unknown The unknown attribute data
+ * @param ptr Pointer to store the pointer to the parameter array (may be NULL)
+ * @return The length of the partial parameter array
+ *
+ * @ingroup sgr
+ */
+size_t ghostty_sgr_unknown_partial(GhosttySgrUnknown unknown,
+ const uint16_t** ptr);
+
+/**
+ * Get the tag from an SGR attribute.
+ *
+ * This function extracts the tag that identifies which type of attribute
+ * this is. Primarily useful in WebAssembly environments where accessing
+ * struct fields directly is difficult.
+ *
+ * @param attr The SGR attribute
+ * @return The attribute tag
+ *
+ * @ingroup sgr
+ */
+GhosttySgrAttributeTag ghostty_sgr_attribute_tag(GhosttySgrAttribute attr);
+
+/**
+ * Get the value from an SGR attribute.
+ *
+ * This function returns a pointer to the value union from an SGR attribute. Use
+ * the tag to determine which field of the union is valid. Primarily useful in
+ * WebAssembly environments where accessing struct fields directly is difficult.
+ *
+ * @param attr Pointer to the SGR attribute
+ * @return Pointer to the attribute value union
+ *
+ * @ingroup sgr
+ */
+GhosttySgrAttributeValue* ghostty_sgr_attribute_value(
+ GhosttySgrAttribute* attr);
+
+#ifdef __wasm__
+/**
+ * Allocate memory for an SGR attribute (WebAssembly only).
+ *
+ * This is a convenience function for WebAssembly environments to allocate
+ * memory for an SGR attribute structure that can be passed to ghostty_sgr_next.
+ *
+ * @return Pointer to the allocated attribute structure
+ *
+ * @ingroup wasm
+ */
+GhosttySgrAttribute* ghostty_wasm_alloc_sgr_attribute(void);
+
+/**
+ * Free memory for an SGR attribute (WebAssembly only).
+ *
+ * Frees memory allocated by ghostty_wasm_alloc_sgr_attribute.
+ *
+ * @param attr Pointer to the attribute structure to free
+ *
+ * @ingroup wasm
+ */
+void ghostty_wasm_free_sgr_attribute(GhosttySgrAttribute* attr);
+#endif
#ifdef __cplusplus
}
diff --git a/include/ghostty/vt/wasm.h b/include/ghostty/vt/wasm.h
index 7edee529f..37a826326 100644
--- a/include/ghostty/vt/wasm.h
+++ b/include/ghostty/vt/wasm.h
@@ -47,7 +47,7 @@
*
* // Allocate output buffer and size pointer
* const bufferSize = 32;
- * const bufPtr = exports.ghostty_wasm_alloc_buffer(bufferSize);
+ * const bufPtr = exports.ghostty_wasm_alloc_u8_array(bufferSize);
* const writtenPtr = exports.ghostty_wasm_alloc_usize();
*
* // Encode the key event
@@ -85,22 +85,40 @@ void** ghostty_wasm_alloc_opaque(void);
void ghostty_wasm_free_opaque(void **ptr);
/**
- * Allocate a buffer of the specified length.
+ * Allocate an array of uint8_t values.
*
- * @param len Number of bytes to allocate
- * @return Pointer to allocated buffer, or NULL if allocation failed
+ * @param len Number of uint8_t elements to allocate
+ * @return Pointer to allocated array, or NULL if allocation failed
* @ingroup wasm
*/
-uint8_t* ghostty_wasm_alloc_buffer(size_t len);
+uint8_t* ghostty_wasm_alloc_u8_array(size_t len);
/**
- * Free a buffer allocated by ghostty_wasm_alloc_buffer().
+ * Free an array allocated by ghostty_wasm_alloc_u8_array().
*
- * @param ptr Pointer to the buffer to free, or NULL (NULL is safely ignored)
- * @param len Length of the buffer (must match the length passed to alloc)
+ * @param ptr Pointer to the array to free, or NULL (NULL is safely ignored)
+ * @param len Length of the array (must match the length passed to alloc)
* @ingroup wasm
*/
-void ghostty_wasm_free_buffer(uint8_t *ptr, size_t len);
+void ghostty_wasm_free_u8_array(uint8_t *ptr, size_t len);
+
+/**
+ * Allocate an array of uint16_t values.
+ *
+ * @param len Number of uint16_t elements to allocate
+ * @return Pointer to allocated array, or NULL if allocation failed
+ * @ingroup wasm
+ */
+uint16_t* ghostty_wasm_alloc_u16_array(size_t len);
+
+/**
+ * Free an array allocated by ghostty_wasm_alloc_u16_array().
+ *
+ * @param ptr Pointer to the array to free, or NULL (NULL is safely ignored)
+ * @param len Length of the array (must match the length passed to alloc)
+ * @ingroup wasm
+ */
+void ghostty_wasm_free_u16_array(uint16_t *ptr, size_t len);
/**
* Allocate a single uint8_t value.
diff --git a/src/lib/allocator/convenience.zig b/src/lib/allocator/convenience.zig
index 19543ad0e..0f5f88d29 100644
--- a/src/lib/allocator/convenience.zig
+++ b/src/lib/allocator/convenience.zig
@@ -24,12 +24,21 @@ pub fn freeOpaque(ptr: ?*Opaque) callconv(.c) void {
if (ptr) |p| alloc.destroy(p);
}
-pub fn allocBuffer(len: usize) callconv(.c) ?[*]u8 {
+pub fn allocU8Array(len: usize) callconv(.c) ?[*]u8 {
const slice = alloc.alloc(u8, len) catch return null;
return slice.ptr;
}
-pub fn freeBuffer(ptr: ?[*]u8, len: usize) callconv(.c) void {
+pub fn freeU8Array(ptr: ?[*]u8, len: usize) callconv(.c) void {
+ if (ptr) |p| alloc.free(p[0..len]);
+}
+
+pub fn allocU16Array(len: usize) callconv(.c) ?[*]u16 {
+ const slice = alloc.alloc(u16, len) catch return null;
+ return slice.ptr;
+}
+
+pub fn freeU16Array(ptr: ?[*]u16, len: usize) callconv(.c) void {
if (ptr) |p| alloc.free(p[0..len]);
}
diff --git a/src/lib_vt.zig b/src/lib_vt.zig
index e1aa69659..aa37c6110 100644
--- a/src/lib_vt.zig
+++ b/src/lib_vt.zig
@@ -126,23 +126,32 @@ comptime {
@export(&c.osc_command_type, .{ .name = "ghostty_osc_command_type" });
@export(&c.osc_command_data, .{ .name = "ghostty_osc_command_data" });
@export(&c.paste_is_safe, .{ .name = "ghostty_paste_is_safe" });
+ @export(&c.color_rgb_get, .{ .name = "ghostty_color_rgb_get" });
@export(&c.sgr_new, .{ .name = "ghostty_sgr_new" });
@export(&c.sgr_free, .{ .name = "ghostty_sgr_free" });
@export(&c.sgr_reset, .{ .name = "ghostty_sgr_reset" });
@export(&c.sgr_set_params, .{ .name = "ghostty_sgr_set_params" });
@export(&c.sgr_next, .{ .name = "ghostty_sgr_next" });
+ @export(&c.sgr_unknown_full, .{ .name = "ghostty_sgr_unknown_full" });
+ @export(&c.sgr_unknown_partial, .{ .name = "ghostty_sgr_unknown_partial" });
+ @export(&c.sgr_attribute_tag, .{ .name = "ghostty_sgr_attribute_tag" });
+ @export(&c.sgr_attribute_value, .{ .name = "ghostty_sgr_attribute_value" });
// On Wasm we need to export our allocator convenience functions.
if (builtin.target.cpu.arch.isWasm()) {
const alloc = @import("lib/allocator/convenience.zig");
@export(&alloc.allocOpaque, .{ .name = "ghostty_wasm_alloc_opaque" });
@export(&alloc.freeOpaque, .{ .name = "ghostty_wasm_free_opaque" });
- @export(&alloc.allocBuffer, .{ .name = "ghostty_wasm_alloc_buffer" });
- @export(&alloc.freeBuffer, .{ .name = "ghostty_wasm_free_buffer" });
+ @export(&alloc.allocU8Array, .{ .name = "ghostty_wasm_alloc_u8_array" });
+ @export(&alloc.freeU8Array, .{ .name = "ghostty_wasm_free_u8_array" });
+ @export(&alloc.allocU16Array, .{ .name = "ghostty_wasm_alloc_u16_array" });
+ @export(&alloc.freeU16Array, .{ .name = "ghostty_wasm_free_u16_array" });
@export(&alloc.allocU8, .{ .name = "ghostty_wasm_alloc_u8" });
@export(&alloc.freeU8, .{ .name = "ghostty_wasm_free_u8" });
@export(&alloc.allocUsize, .{ .name = "ghostty_wasm_alloc_usize" });
@export(&alloc.freeUsize, .{ .name = "ghostty_wasm_free_usize" });
+ @export(&c.wasm_alloc_sgr_attribute, .{ .name = "ghostty_wasm_alloc_sgr_attribute" });
+ @export(&c.wasm_free_sgr_attribute, .{ .name = "ghostty_wasm_free_sgr_attribute" });
}
}
}
diff --git a/src/terminal/c/color.zig b/src/terminal/c/color.zig
new file mode 100644
index 000000000..199339706
--- /dev/null
+++ b/src/terminal/c/color.zig
@@ -0,0 +1,12 @@
+const color = @import("../color.zig");
+
+pub fn rgb_get(
+ c: color.RGB.C,
+ r: *u8,
+ g: *u8,
+ b: *u8,
+) callconv(.c) void {
+ r.* = c.r;
+ g.* = c.g;
+ b.* = c.b;
+}
diff --git a/src/terminal/c/main.zig b/src/terminal/c/main.zig
index b935b264d..bc92597f5 100644
--- a/src/terminal/c/main.zig
+++ b/src/terminal/c/main.zig
@@ -1,3 +1,4 @@
+pub const color = @import("color.zig");
pub const osc = @import("osc.zig");
pub const key_event = @import("key_event.zig");
pub const key_encode = @import("key_encode.zig");
@@ -13,11 +14,19 @@ pub const osc_end = osc.end;
pub const osc_command_type = osc.commandType;
pub const osc_command_data = osc.commandData;
+pub const color_rgb_get = color.rgb_get;
+
pub const sgr_new = sgr.new;
pub const sgr_free = sgr.free;
pub const sgr_reset = sgr.reset;
pub const sgr_set_params = sgr.setParams;
pub const sgr_next = sgr.next;
+pub const sgr_unknown_full = sgr.unknown_full;
+pub const sgr_unknown_partial = sgr.unknown_partial;
+pub const sgr_attribute_tag = sgr.attribute_tag;
+pub const sgr_attribute_value = sgr.attribute_value;
+pub const wasm_alloc_sgr_attribute = sgr.wasm_alloc_attribute;
+pub const wasm_free_sgr_attribute = sgr.wasm_free_attribute;
pub const key_event_new = key_event.new;
pub const key_event_free = key_event.free;
@@ -44,6 +53,7 @@ pub const key_encoder_encode = key_encode.encode;
pub const paste_is_safe = paste.is_safe;
test {
+ _ = color;
_ = osc;
_ = key_event;
_ = key_encode;
diff --git a/src/terminal/c/sgr.zig b/src/terminal/c/sgr.zig
index f01a8a25b..e65b9e3ee 100644
--- a/src/terminal/c/sgr.zig
+++ b/src/terminal/c/sgr.zig
@@ -100,6 +100,45 @@ pub fn next(
return false;
}
+pub fn unknown_full(
+ unknown: sgr.Attribute.Unknown.C,
+ ptr: ?*[*]const u16,
+) callconv(.c) usize {
+ if (ptr) |p| p.* = unknown.full_ptr;
+ return unknown.full_len;
+}
+
+pub fn unknown_partial(
+ unknown: sgr.Attribute.Unknown.C,
+ ptr: ?*[*]const u16,
+) callconv(.c) usize {
+ if (ptr) |p| p.* = unknown.partial_ptr;
+ return unknown.partial_len;
+}
+
+pub fn attribute_tag(
+ attr: sgr.Attribute.C,
+) callconv(.c) sgr.Attribute.Tag {
+ return attr.tag;
+}
+
+pub fn attribute_value(
+ attr: *sgr.Attribute.C,
+) callconv(.c) *sgr.Attribute.CValue {
+ return &attr.value;
+}
+
+pub fn wasm_alloc_attribute() callconv(.c) *sgr.Attribute.C {
+ const alloc = std.heap.wasm_allocator;
+ const ptr = alloc.create(sgr.Attribute.C) catch @panic("out of memory");
+ return ptr;
+}
+
+pub fn wasm_free_attribute(attr: *sgr.Attribute.C) callconv(.c) void {
+ const alloc = std.heap.wasm_allocator;
+ alloc.destroy(attr);
+}
+
test "alloc" {
var p: Parser = undefined;
try testing.expectEqual(Result.success, new(