mirror of
https://github.com/oven-sh/bun
synced 2026-02-17 22:32:06 +00:00
Compare commits
4 Commits
claude/fix
...
claude/fix
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e3adf88615 | ||
|
|
4250ce6157 | ||
|
|
f8dce87f24 | ||
|
|
359f04d81f |
8
packages/bun-types/bun.d.ts
vendored
8
packages/bun-types/bun.d.ts
vendored
@@ -5791,11 +5791,11 @@ declare module "bun" {
|
||||
* @category Process Management
|
||||
*
|
||||
* ```js
|
||||
* const subprocess = Bun.spawn({
|
||||
* const proc = Bun.spawn({
|
||||
* cmd: ["echo", "hello"],
|
||||
* stdout: "pipe",
|
||||
* });
|
||||
* const text = await readableStreamToText(subprocess.stdout);
|
||||
* const text = await proc.stdout.text();
|
||||
* console.log(text); // "hello\n"
|
||||
* ```
|
||||
*
|
||||
@@ -5829,8 +5829,8 @@ declare module "bun" {
|
||||
* Spawn a new process
|
||||
*
|
||||
* ```js
|
||||
* const {stdout} = Bun.spawn(["echo", "hello"]);
|
||||
* const text = await readableStreamToText(stdout);
|
||||
* const proc = Bun.spawn(["echo", "hello"]);
|
||||
* const text = await proc.stdout.text();
|
||||
* console.log(text); // "hello\n"
|
||||
* ```
|
||||
*
|
||||
|
||||
2
packages/bun-types/test.d.ts
vendored
2
packages/bun-types/test.d.ts
vendored
@@ -172,7 +172,7 @@ declare module "bun:test" {
|
||||
/**
|
||||
* Mock a module
|
||||
*/
|
||||
module: typeof mock.module;
|
||||
mock: typeof mock.module;
|
||||
/**
|
||||
* Restore all mocks to their original implementation
|
||||
*/
|
||||
|
||||
@@ -416,8 +416,7 @@ extern "C" napi_status napi_set_property(napi_env env, napi_value target,
|
||||
|
||||
JSValue jsValue = toJS(value);
|
||||
|
||||
// Ignoring the return value matches JS sloppy mode
|
||||
(void)object->methodTable()->put(object, globalObject, identifier, jsValue, slot);
|
||||
(void)object->putInline(globalObject, identifier, jsValue, slot);
|
||||
NAPI_RETURN_SUCCESS_UNLESS_EXCEPTION(env);
|
||||
}
|
||||
|
||||
@@ -432,12 +431,12 @@ extern "C" napi_status napi_set_element(napi_env env, napi_value object_,
|
||||
JSValue value = toJS(value_);
|
||||
NAPI_RETURN_EARLY_IF_FALSE(env, !object.isEmpty() && !value.isEmpty(), napi_invalid_arg);
|
||||
|
||||
auto globalObject = toJS(env);
|
||||
JSObject* jsObject = object.getObject();
|
||||
NAPI_RETURN_EARLY_IF_FALSE(env, jsObject, napi_array_expected);
|
||||
|
||||
jsObject->methodTable()->putByIndex(jsObject, toJS(env), index, value, false);
|
||||
NAPI_RETURN_IF_EXCEPTION(env);
|
||||
NAPI_RETURN_SUCCESS(env);
|
||||
(void)jsObject->putByIndexInline(globalObject, index, value, false);
|
||||
NAPI_RETURN_SUCCESS_UNLESS_EXCEPTION(env);
|
||||
}
|
||||
|
||||
extern "C" napi_status napi_has_element(napi_env env, napi_value object_,
|
||||
@@ -454,9 +453,9 @@ extern "C" napi_status napi_has_element(napi_env env, napi_value object_,
|
||||
NAPI_RETURN_EARLY_IF_FALSE(env, jsObject, napi_array_expected);
|
||||
|
||||
bool has_property = jsObject->hasProperty(toJS(env), index);
|
||||
NAPI_RETURN_IF_EXCEPTION(env);
|
||||
*result = has_property;
|
||||
|
||||
NAPI_RETURN_SUCCESS_UNLESS_EXCEPTION(env);
|
||||
NAPI_RETURN_SUCCESS(env);
|
||||
}
|
||||
|
||||
extern "C" napi_status napi_has_property(napi_env env, napi_value object,
|
||||
@@ -472,8 +471,13 @@ extern "C" napi_status napi_has_property(napi_env env, napi_value object,
|
||||
NAPI_RETURN_IF_EXCEPTION(env);
|
||||
|
||||
auto keyProp = toJS(key);
|
||||
*result = target->hasProperty(globalObject, keyProp.toPropertyKey(globalObject));
|
||||
NAPI_RETURN_SUCCESS_UNLESS_EXCEPTION(env);
|
||||
JSC::PropertyName name = keyProp.toPropertyKey(globalObject);
|
||||
NAPI_RETURN_IF_EXCEPTION(env);
|
||||
|
||||
bool hasProperty = target->hasProperty(globalObject, name);
|
||||
NAPI_RETURN_IF_EXCEPTION(env);
|
||||
*result = hasProperty;
|
||||
NAPI_RETURN_SUCCESS(env);
|
||||
}
|
||||
|
||||
extern "C" napi_status napi_get_date_value(napi_env env, napi_value value, double* result)
|
||||
@@ -507,8 +511,26 @@ extern "C" napi_status napi_get_property(napi_env env, napi_value object,
|
||||
|
||||
auto keyProp = toJS(key);
|
||||
JSC::EnsureStillAliveScope ensureAlive2(keyProp);
|
||||
*result = toNapi(target->get(globalObject, keyProp.toPropertyKey(globalObject)), globalObject);
|
||||
NAPI_RETURN_SUCCESS_UNLESS_EXCEPTION(env);
|
||||
PropertySlot slot(target, PropertySlot::InternalMethodType::Get);
|
||||
auto propertyName = keyProp.toPropertyKey(globalObject);
|
||||
NAPI_RETURN_IF_EXCEPTION(env);
|
||||
|
||||
const auto index = parseIndex(propertyName);
|
||||
|
||||
bool hasProperty = index ? target->getPropertySlot(globalObject, *index, slot)
|
||||
: target->getNonIndexPropertySlot(globalObject, propertyName, slot);
|
||||
|
||||
NAPI_RETURN_IF_EXCEPTION(env);
|
||||
|
||||
if (!hasProperty) {
|
||||
*result = toNapi(jsUndefined(), globalObject);
|
||||
} else {
|
||||
JSValue resultValue = slot.getValue(globalObject, propertyName);
|
||||
NAPI_RETURN_IF_EXCEPTION(env);
|
||||
*result = toNapi(resultValue, globalObject);
|
||||
}
|
||||
|
||||
NAPI_RETURN_SUCCESS(env);
|
||||
}
|
||||
|
||||
extern "C" napi_status napi_delete_property(napi_env env, napi_value object,
|
||||
@@ -524,7 +546,11 @@ extern "C" napi_status napi_delete_property(napi_env env, napi_value object,
|
||||
NAPI_RETURN_IF_EXCEPTION(env);
|
||||
|
||||
auto keyProp = toJS(key);
|
||||
auto deleteResult = target->deleteProperty(globalObject, keyProp.toPropertyKey(globalObject));
|
||||
auto name = JSC::PropertyName(keyProp.toPropertyKey(globalObject));
|
||||
NAPI_RETURN_IF_EXCEPTION(env);
|
||||
|
||||
auto deleteResult = target->deleteProperty(globalObject, name);
|
||||
|
||||
NAPI_RETURN_IF_EXCEPTION(env);
|
||||
|
||||
if (result) [[likely]] {
|
||||
@@ -550,8 +576,13 @@ extern "C" napi_status napi_has_own_property(napi_env env, napi_value object,
|
||||
JSValue keyProp = toJS(key);
|
||||
NAPI_RETURN_EARLY_IF_FALSE(env, keyProp.isString() || keyProp.isSymbol(), napi_name_expected);
|
||||
|
||||
*result = target->hasOwnProperty(globalObject, JSC::PropertyName(keyProp.toPropertyKey(globalObject)));
|
||||
NAPI_RETURN_SUCCESS_UNLESS_EXCEPTION(env);
|
||||
auto name = JSC::PropertyName(keyProp.toPropertyKey(globalObject));
|
||||
NAPI_RETURN_IF_EXCEPTION(env);
|
||||
|
||||
bool hasOwnProperty = target->hasOwnProperty(globalObject, name);
|
||||
NAPI_RETURN_IF_EXCEPTION(env);
|
||||
*result = hasOwnProperty;
|
||||
NAPI_RETURN_SUCCESS(env);
|
||||
}
|
||||
|
||||
extern "C" napi_status napi_set_named_property(napi_env env, napi_value object,
|
||||
@@ -575,11 +606,10 @@ extern "C" napi_status napi_set_named_property(napi_env env, napi_value object,
|
||||
JSC::EnsureStillAliveScope ensureAlive2(target);
|
||||
|
||||
auto nameStr = WTF::String::fromUTF8({ utf8name, strlen(utf8name) });
|
||||
auto identifier = JSC::Identifier::fromString(vm, WTFMove(nameStr));
|
||||
|
||||
auto name = JSC::PropertyName(JSC::Identifier::fromString(vm, WTFMove(nameStr)));
|
||||
PutPropertySlot slot(target, false);
|
||||
|
||||
target->methodTable()->put(target, globalObject, identifier, jsValue, slot);
|
||||
target->putInline(globalObject, name, jsValue, slot);
|
||||
NAPI_RETURN_SUCCESS_UNLESS_EXCEPTION(env);
|
||||
}
|
||||
|
||||
|
||||
@@ -657,11 +657,19 @@ pub const visible = struct {
|
||||
length += visibleLatin1Width(input[0..i]);
|
||||
input = input[i..];
|
||||
|
||||
if (input.len < 3) return length;
|
||||
if (input.len < 3) {
|
||||
length += visibleLatin1Width(input);
|
||||
return length;
|
||||
}
|
||||
|
||||
if (input[1] == '[') {
|
||||
const end = indexFn(input[2..], 'm') orelse return length;
|
||||
input = input[end + 3 ..];
|
||||
if (indexFn(input[2..], 'm')) |end| {
|
||||
input = input[end + 3 ..];
|
||||
} else {
|
||||
// No closing 'm' found, treat the rest as visible characters
|
||||
length += visibleLatin1Width(input);
|
||||
return length;
|
||||
}
|
||||
} else {
|
||||
input = input[1..];
|
||||
}
|
||||
@@ -756,10 +764,19 @@ pub const visible = struct {
|
||||
saw_1b = true;
|
||||
continue;
|
||||
}
|
||||
len += stretch_len;
|
||||
// If we're not in the middle of an ANSI sequence, add stretch_len and reset
|
||||
// If we ARE in a sequence (saw_bracket is true), keep accumulating in stretch_len
|
||||
if (!saw_bracket) {
|
||||
len += stretch_len;
|
||||
stretch_len = 0;
|
||||
}
|
||||
input = input[idx..];
|
||||
}
|
||||
if (input.len == 0) break;
|
||||
if (input.len == 0) {
|
||||
// If we reach the end with an unclosed ANSI sequence, count the accumulated characters
|
||||
len += stretch_len;
|
||||
break;
|
||||
}
|
||||
const replacement = utf16CodepointWithFFFD(input);
|
||||
defer input = input[replacement.len..];
|
||||
if (replacement.fail) continue;
|
||||
|
||||
@@ -149,3 +149,37 @@ for (let matcher of ["toMatchNPMStringWidth", "toMatchNPMStringWidthExcludeANSI"
|
||||
expect("👨❤️💋👨")[matcher]();
|
||||
});
|
||||
}
|
||||
|
||||
// Test for strings with control characters and binary data (from gist)
|
||||
test("handles binary data with control characters", () => {
|
||||
// This string caused freezing issues in earlier versions
|
||||
const problematicString = `com.apple.lastuseddate#PS: S<>\u000bi\ncom.apple.macl: \x07@<40><>Y6<59>>J<><4A>'<27><>\x03<EFBFBD>FS\ncom.apple.metadata:kMDItemWhereFroms: bplist00<30>\x01\x02_\x11\x02\x04https://software.download.prss.microsoft.com/dbazure/Win11_25H2_English_Arm64.iso?t=984c522c-a10b-41d5-99ec-68cc848694c9&P1=1762014682&P2=601&P3=2&P4=G6eN0uFrG64Ft%2bDz061PD0rTvYV2UQjZUVtyS9Rn9Ytt0F%2bscgadBtf%2fUs5BKFyowVlDqPhEbTtqBsPEk21bgNAyRwBj%2fgnQcRhiIwEcqSJ9Wyf4ChE%2bYRuc0Eeha9IJakJwuBizc38a4qKsEIxihqroM01TM8iANCExlWWZKG3Gayc%2b18OcvGefTc1G%2bvtvd57AWmeK1kho00yTFtT1sqdS6OXV000YyaYoIVLjVypaoQj7MYJ46vCQb%2bVvn3QZgXaMVwbKjCMI15ezgpGptQPWBssWz9hYC9Fv1OuWcmBwvLGkvL1MczAWSuY3P0kqfezG%2fdkh2cX5NUo2G3zPtw%3d%3d_\x10\x1ahttps://www.microsoft.com/\ncom.apple.provenance: \x01\x02\n`;
|
||||
|
||||
// Should not freeze and should return a reasonable width
|
||||
const width = Bun.stringWidth(problematicString);
|
||||
expect(width).toBeGreaterThan(0);
|
||||
expect(width).toBeLessThan(problematicString.length + 100);
|
||||
|
||||
// Also test with countAnsiEscapeCodes: false (the default)
|
||||
const width2 = Bun.stringWidth(problematicString, { countAnsiEscapeCodes: false });
|
||||
expect(width2).toBeGreaterThan(0);
|
||||
expect(width2).toBeLessThan(problematicString.length + 100);
|
||||
});
|
||||
|
||||
// Test edge cases with malformed ANSI sequences
|
||||
test("handles malformed ANSI sequences", () => {
|
||||
// ESC without [
|
||||
expect(Bun.stringWidth("\x1bHello")).toBeGreaterThan(0);
|
||||
|
||||
// ESC [ without closing m
|
||||
expect(Bun.stringWidth("\x1b[31Hello")).toBeGreaterThan(0);
|
||||
|
||||
// ESC [ with other characters but no m
|
||||
expect(Bun.stringWidth("\x1b[31;32;33Hello")).toBeGreaterThan(0);
|
||||
|
||||
// Multiple unclosed sequences
|
||||
expect(Bun.stringWidth("\x1b[31\x1b[32\x1b[33Hello")).toBeGreaterThan(0);
|
||||
|
||||
// Control characters mixed with text
|
||||
expect(Bun.stringWidth("\x01\x02\x03Hello\x07\x0b\x10\x1aWorld")).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
@@ -554,6 +554,386 @@ static napi_value test_is_typedarray(const Napi::CallbackInfo &info) {
|
||||
return ok(env);
|
||||
}
|
||||
|
||||
static napi_value test_napi_get_default_values(const Napi::CallbackInfo &info) {
|
||||
napi_env env = info.Env();
|
||||
|
||||
#ifndef _WIN32
|
||||
BlockingStdoutScope stdout_scope;
|
||||
#endif
|
||||
|
||||
napi_value obj;
|
||||
NODE_API_CALL(env, napi_create_object(env, &obj));
|
||||
|
||||
// Test 1: Get property that doesn't exist (should return undefined)
|
||||
napi_value unknown_key;
|
||||
NODE_API_CALL(env, napi_create_string_utf8(env, "nonexistent",
|
||||
NAPI_AUTO_LENGTH, &unknown_key));
|
||||
|
||||
napi_value result;
|
||||
napi_status get_status = napi_get_property(env, obj, unknown_key, &result);
|
||||
|
||||
if (get_status == napi_ok) {
|
||||
napi_valuetype result_type;
|
||||
napi_status type_status = napi_typeof(env, result, &result_type);
|
||||
|
||||
if (type_status == napi_ok && result_type == napi_undefined) {
|
||||
printf("PASS: napi_get_property for unknown key returned undefined\n");
|
||||
} else {
|
||||
printf("FAIL: napi_get_property for unknown key returned type %d "
|
||||
"(expected napi_undefined)\n",
|
||||
result_type);
|
||||
}
|
||||
} else {
|
||||
printf("FAIL: napi_get_property for unknown key failed with status %d\n",
|
||||
get_status);
|
||||
}
|
||||
|
||||
// Test 2: Get element at index that doesn't exist on array
|
||||
napi_value array;
|
||||
NODE_API_CALL(env, napi_create_array_with_length(env, 2, &array));
|
||||
|
||||
napi_value element_result;
|
||||
napi_status element_status = napi_get_element(env, array, 5, &element_result);
|
||||
|
||||
if (element_status == napi_ok) {
|
||||
napi_valuetype element_type;
|
||||
napi_status element_type_status =
|
||||
napi_typeof(env, element_result, &element_type);
|
||||
|
||||
if (element_type_status == napi_ok && element_type == napi_undefined) {
|
||||
printf("PASS: napi_get_element for out-of-bounds index returned "
|
||||
"undefined\n");
|
||||
} else {
|
||||
printf("FAIL: napi_get_element for out-of-bounds index returned type %d "
|
||||
"(expected napi_undefined)\n",
|
||||
element_type);
|
||||
}
|
||||
} else {
|
||||
printf("FAIL: napi_get_element for out-of-bounds index failed with status "
|
||||
"%d\n",
|
||||
element_status);
|
||||
}
|
||||
|
||||
// Test 3: Get named property that doesn't exist
|
||||
napi_value named_result;
|
||||
napi_status named_status =
|
||||
napi_get_named_property(env, obj, "missing_prop", &named_result);
|
||||
|
||||
if (named_status == napi_ok) {
|
||||
napi_valuetype named_type;
|
||||
napi_status named_type_status = napi_typeof(env, named_result, &named_type);
|
||||
|
||||
if (named_type_status == napi_ok && named_type == napi_undefined) {
|
||||
printf("PASS: napi_get_named_property for unknown property returned "
|
||||
"undefined\n");
|
||||
} else {
|
||||
printf("FAIL: napi_get_named_property for unknown property returned type "
|
||||
"%d (expected napi_undefined)\n",
|
||||
named_type);
|
||||
}
|
||||
} else {
|
||||
printf("FAIL: napi_get_named_property for unknown property failed with "
|
||||
"status %d\n",
|
||||
named_status);
|
||||
}
|
||||
|
||||
// Test 4: Set a property and verify we can get it back
|
||||
napi_value test_key;
|
||||
napi_value test_value;
|
||||
NODE_API_CALL(env, napi_create_string_utf8(env, "test_key", NAPI_AUTO_LENGTH,
|
||||
&test_key));
|
||||
NODE_API_CALL(env, napi_create_int32(env, 42, &test_value));
|
||||
|
||||
NODE_API_CALL(env, napi_set_property(env, obj, test_key, test_value));
|
||||
|
||||
napi_value retrieved_value;
|
||||
NODE_API_CALL(env, napi_get_property(env, obj, test_key, &retrieved_value));
|
||||
|
||||
int32_t retrieved_int;
|
||||
napi_status int_status =
|
||||
napi_get_value_int32(env, retrieved_value, &retrieved_int);
|
||||
|
||||
if (int_status == napi_ok && retrieved_int == 42) {
|
||||
printf("PASS: napi_get_property correctly retrieved set value: %d\n",
|
||||
retrieved_int);
|
||||
} else {
|
||||
printf("FAIL: napi_get_property did not retrieve correct value (got %d, "
|
||||
"expected 42)\n",
|
||||
retrieved_int);
|
||||
}
|
||||
|
||||
// Test 5: Use integer as property key (should be converted to string)
|
||||
napi_value int_key;
|
||||
napi_value int_key_value;
|
||||
NODE_API_CALL(env, napi_create_int32(env, 123, &int_key));
|
||||
NODE_API_CALL(env, napi_create_string_utf8(env, "integer_key_value",
|
||||
NAPI_AUTO_LENGTH, &int_key_value));
|
||||
|
||||
// Set property using integer key
|
||||
napi_status int_key_set_status =
|
||||
napi_set_property(env, obj, int_key, int_key_value);
|
||||
|
||||
if (int_key_set_status == napi_ok) {
|
||||
printf("PASS: napi_set_property with integer key succeeded\n");
|
||||
|
||||
// Try to get it back using the same integer key
|
||||
napi_value int_key_result;
|
||||
napi_status int_key_get_status =
|
||||
napi_get_property(env, obj, int_key, &int_key_result);
|
||||
|
||||
if (int_key_get_status == napi_ok) {
|
||||
// Check if we got back a string
|
||||
napi_valuetype int_key_result_type;
|
||||
napi_status int_key_type_status =
|
||||
napi_typeof(env, int_key_result, &int_key_result_type);
|
||||
|
||||
if (int_key_type_status == napi_ok &&
|
||||
int_key_result_type == napi_string) {
|
||||
char buffer[256];
|
||||
size_t copied;
|
||||
napi_status str_status = napi_get_value_string_utf8(
|
||||
env, int_key_result, buffer, sizeof(buffer), &copied);
|
||||
|
||||
if (str_status == napi_ok && strcmp(buffer, "integer_key_value") == 0) {
|
||||
printf("PASS: napi_get_property with integer key retrieved correct "
|
||||
"value: %s\n",
|
||||
buffer);
|
||||
} else {
|
||||
printf("FAIL: napi_get_property with integer key retrieved wrong "
|
||||
"value: %s\n",
|
||||
buffer);
|
||||
}
|
||||
} else {
|
||||
printf("FAIL: napi_get_property with integer key returned type %d "
|
||||
"(expected string)\n",
|
||||
int_key_result_type);
|
||||
}
|
||||
} else {
|
||||
printf("FAIL: napi_get_property with integer key failed with status %d\n",
|
||||
int_key_get_status);
|
||||
}
|
||||
|
||||
// Also try to get it using string "123"
|
||||
napi_value string_123_key;
|
||||
NODE_API_CALL(env, napi_create_string_utf8(env, "123", NAPI_AUTO_LENGTH,
|
||||
&string_123_key));
|
||||
|
||||
napi_value string_key_result;
|
||||
napi_status string_key_get_status =
|
||||
napi_get_property(env, obj, string_123_key, &string_key_result);
|
||||
|
||||
if (string_key_get_status == napi_ok) {
|
||||
napi_valuetype string_key_result_type;
|
||||
napi_status string_key_type_status =
|
||||
napi_typeof(env, string_key_result, &string_key_result_type);
|
||||
|
||||
if (string_key_type_status == napi_ok &&
|
||||
string_key_result_type == napi_string) {
|
||||
char buffer2[256];
|
||||
size_t copied2;
|
||||
napi_status str_status2 = napi_get_value_string_utf8(
|
||||
env, string_key_result, buffer2, sizeof(buffer2), &copied2);
|
||||
|
||||
if (str_status2 == napi_ok &&
|
||||
strcmp(buffer2, "integer_key_value") == 0) {
|
||||
printf("PASS: napi_get_property with string '123' key also retrieved "
|
||||
"correct value: %s\n",
|
||||
buffer2);
|
||||
} else {
|
||||
printf("FAIL: napi_get_property with string '123' key retrieved "
|
||||
"wrong value: %s\n",
|
||||
buffer2);
|
||||
}
|
||||
} else {
|
||||
printf("FAIL: napi_get_property with string '123' key returned type %d "
|
||||
"(expected string)\n",
|
||||
string_key_result_type);
|
||||
}
|
||||
} else {
|
||||
printf("FAIL: napi_get_property with string '123' key failed with status "
|
||||
"%d\n",
|
||||
string_key_get_status);
|
||||
}
|
||||
} else {
|
||||
printf("FAIL: napi_set_property with integer key failed with status %d\n",
|
||||
int_key_set_status);
|
||||
}
|
||||
|
||||
return ok(env);
|
||||
}
|
||||
|
||||
static napi_value
|
||||
test_napi_numeric_string_keys(const Napi::CallbackInfo &info) {
|
||||
napi_env env = info.Env();
|
||||
|
||||
#ifndef _WIN32
|
||||
BlockingStdoutScope stdout_scope;
|
||||
#endif
|
||||
|
||||
napi_value obj;
|
||||
NODE_API_CALL(env, napi_create_object(env, &obj));
|
||||
|
||||
// Test setting property with numeric string key "0"
|
||||
napi_value value_123;
|
||||
NODE_API_CALL(env, napi_create_int32(env, 123, &value_123));
|
||||
|
||||
napi_status set_status = napi_set_named_property(env, obj, "0", value_123);
|
||||
if (set_status == napi_ok) {
|
||||
printf("PASS: napi_set_named_property with key '0' succeeded\n");
|
||||
} else {
|
||||
printf("FAIL: napi_set_named_property with key '0' failed: %d\n",
|
||||
set_status);
|
||||
}
|
||||
|
||||
// Test has property with numeric string key "0"
|
||||
bool has_prop;
|
||||
napi_status has_status = napi_has_named_property(env, obj, "0", &has_prop);
|
||||
if (has_status == napi_ok && has_prop) {
|
||||
printf("PASS: napi_has_named_property with key '0' returned true\n");
|
||||
} else {
|
||||
printf("FAIL: napi_has_named_property with key '0' failed or returned "
|
||||
"false: status=%d, has=%s\n",
|
||||
has_status, has_prop ? "true" : "false");
|
||||
}
|
||||
|
||||
// Test getting property with numeric string key "0"
|
||||
napi_value retrieved_value;
|
||||
napi_status get_status =
|
||||
napi_get_named_property(env, obj, "0", &retrieved_value);
|
||||
if (get_status == napi_ok) {
|
||||
int32_t retrieved_int;
|
||||
napi_status int_status =
|
||||
napi_get_value_int32(env, retrieved_value, &retrieved_int);
|
||||
if (int_status == napi_ok && retrieved_int == 123) {
|
||||
printf("PASS: napi_get_named_property with key '0' returned correct "
|
||||
"value: %d\n",
|
||||
retrieved_int);
|
||||
} else {
|
||||
printf("FAIL: napi_get_named_property with key '0' returned wrong value: "
|
||||
"status=%d, value=%d\n",
|
||||
int_status, retrieved_int);
|
||||
}
|
||||
} else {
|
||||
printf("FAIL: napi_get_named_property with key '0' failed: %d\n",
|
||||
get_status);
|
||||
}
|
||||
|
||||
// Test with another numeric string key "1"
|
||||
napi_value value_456;
|
||||
NODE_API_CALL(env, napi_create_int32(env, 456, &value_456));
|
||||
|
||||
set_status = napi_set_named_property(env, obj, "1", value_456);
|
||||
if (set_status == napi_ok) {
|
||||
printf("PASS: napi_set_named_property with key '1' succeeded\n");
|
||||
} else {
|
||||
printf("FAIL: napi_set_named_property with key '1' failed: %d\n",
|
||||
set_status);
|
||||
}
|
||||
|
||||
has_status = napi_has_named_property(env, obj, "1", &has_prop);
|
||||
if (has_status == napi_ok && has_prop) {
|
||||
printf("PASS: napi_has_named_property with key '1' returned true\n");
|
||||
} else {
|
||||
printf("FAIL: napi_has_named_property with key '1' failed or returned "
|
||||
"false: status=%d, has=%s\n",
|
||||
has_status, has_prop ? "true" : "false");
|
||||
}
|
||||
|
||||
get_status = napi_get_named_property(env, obj, "1", &retrieved_value);
|
||||
if (get_status == napi_ok) {
|
||||
int32_t retrieved_int;
|
||||
napi_status int_status =
|
||||
napi_get_value_int32(env, retrieved_value, &retrieved_int);
|
||||
if (int_status == napi_ok && retrieved_int == 456) {
|
||||
printf("PASS: napi_get_named_property with key '1' returned correct "
|
||||
"value: %d\n",
|
||||
retrieved_int);
|
||||
} else {
|
||||
printf("FAIL: napi_get_named_property with key '1' returned wrong value: "
|
||||
"status=%d, value=%d\n",
|
||||
int_status, retrieved_int);
|
||||
}
|
||||
} else {
|
||||
printf("FAIL: napi_get_named_property with key '1' failed: %d\n",
|
||||
get_status);
|
||||
}
|
||||
|
||||
// Test with napi_get_property using numeric string keys
|
||||
napi_value key_0, key_1;
|
||||
NODE_API_CALL(env,
|
||||
napi_create_string_utf8(env, "0", NAPI_AUTO_LENGTH, &key_0));
|
||||
NODE_API_CALL(env,
|
||||
napi_create_string_utf8(env, "1", NAPI_AUTO_LENGTH, &key_1));
|
||||
|
||||
napi_value prop_value;
|
||||
napi_status prop_status = napi_get_property(env, obj, key_0, &prop_value);
|
||||
if (prop_status == napi_ok) {
|
||||
int32_t prop_int;
|
||||
napi_status int_status = napi_get_value_int32(env, prop_value, &prop_int);
|
||||
if (int_status == napi_ok && prop_int == 123) {
|
||||
printf(
|
||||
"PASS: napi_get_property with key '0' returned correct value: %d\n",
|
||||
prop_int);
|
||||
} else {
|
||||
printf("FAIL: napi_get_property with key '0' returned wrong value: "
|
||||
"status=%d, value=%d\n",
|
||||
int_status, prop_int);
|
||||
}
|
||||
} else {
|
||||
printf("FAIL: napi_get_property with key '0' failed: %d\n", prop_status);
|
||||
}
|
||||
|
||||
// Test napi_has_property
|
||||
bool has_property;
|
||||
napi_status has_prop_status =
|
||||
napi_has_property(env, obj, key_1, &has_property);
|
||||
if (has_prop_status == napi_ok && has_property) {
|
||||
printf("PASS: napi_has_property with key '1' returned true\n");
|
||||
} else {
|
||||
printf("FAIL: napi_has_property with key '1' failed or returned false: "
|
||||
"status=%d, has=%s\n",
|
||||
has_prop_status, has_property ? "true" : "false");
|
||||
}
|
||||
|
||||
// Test napi_has_own_property
|
||||
bool has_own_property;
|
||||
napi_status has_own_status =
|
||||
napi_has_own_property(env, obj, key_0, &has_own_property);
|
||||
if (has_own_status == napi_ok && has_own_property) {
|
||||
printf("PASS: napi_has_own_property with key '0' returned true\n");
|
||||
} else {
|
||||
printf("FAIL: napi_has_own_property with key '0' failed or returned false: "
|
||||
"status=%d, has=%s\n",
|
||||
has_own_status, has_own_property ? "true" : "false");
|
||||
}
|
||||
|
||||
// Test napi_delete_property
|
||||
bool delete_result;
|
||||
napi_status delete_status =
|
||||
napi_delete_property(env, obj, key_1, &delete_result);
|
||||
if (delete_status == napi_ok) {
|
||||
printf("PASS: napi_delete_property with key '1' succeeded, result=%s\n",
|
||||
delete_result ? "true" : "false");
|
||||
|
||||
// Verify the property was actually deleted
|
||||
bool still_has_property;
|
||||
napi_status verify_status =
|
||||
napi_has_property(env, obj, key_1, &still_has_property);
|
||||
if (verify_status == napi_ok && !still_has_property) {
|
||||
printf("PASS: Property '1' was successfully deleted\n");
|
||||
} else {
|
||||
printf(
|
||||
"FAIL: Property '1' still exists after deletion: status=%d, has=%s\n",
|
||||
verify_status, still_has_property ? "true" : "false");
|
||||
}
|
||||
} else {
|
||||
printf("FAIL: napi_delete_property with key '1' failed: %d\n",
|
||||
delete_status);
|
||||
}
|
||||
|
||||
return ok(env);
|
||||
}
|
||||
|
||||
static napi_value test_deferred_exceptions(const Napi::CallbackInfo &info) {
|
||||
napi_env env = info.Env();
|
||||
|
||||
@@ -1466,6 +1846,8 @@ void register_standalone_tests(Napi::Env env, Napi::Object exports) {
|
||||
REGISTER_FUNCTION(env, exports, bigint_to_64_null);
|
||||
REGISTER_FUNCTION(env, exports, test_is_buffer);
|
||||
REGISTER_FUNCTION(env, exports, test_is_typedarray);
|
||||
REGISTER_FUNCTION(env, exports, test_napi_get_default_values);
|
||||
REGISTER_FUNCTION(env, exports, test_napi_numeric_string_keys);
|
||||
REGISTER_FUNCTION(env, exports, test_deferred_exceptions);
|
||||
REGISTER_FUNCTION(env, exports, test_napi_strict_equals);
|
||||
REGISTER_FUNCTION(env, exports, test_napi_call_function_recv_null);
|
||||
|
||||
@@ -549,6 +549,14 @@ describe.concurrent("napi", () => {
|
||||
await checkSameOutput("test_deferred_exceptions", []);
|
||||
});
|
||||
|
||||
it("behaves as expected when performing operations with numeric string keys", async () => {
|
||||
await checkSameOutput("test_napi_numeric_string_keys", []);
|
||||
});
|
||||
|
||||
it("behaves as expected when performing operations with default values", async () => {
|
||||
await checkSameOutput("test_napi_get_default_values", []);
|
||||
});
|
||||
|
||||
it("NAPI finalizer iterator invalidation crash prevention", () => {
|
||||
// This test verifies that the DeferGCForAWhile fix prevents iterator invalidation
|
||||
// during NAPI finalizer cleanup. While we couldn't reproduce the exact crash
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { test } from "bun:test";
|
||||
import { basename, dirname, sep } from "node:path";
|
||||
import { build, run } from "../../../harness";
|
||||
|
||||
@@ -6,7 +7,7 @@ test("build", async () => {
|
||||
});
|
||||
|
||||
for (const file of Array.from(new Bun.Glob("*.js").scanSync(import.meta.dir))) {
|
||||
test.todoIf(["test.js"].includes(file))(file, () => {
|
||||
test(file, () => {
|
||||
run(dirname(import.meta.dir), basename(import.meta.dir) + sep + file);
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user