diff options
| author | Thijs Schreijer <thijs@thijsschreijer.nl> | 2026-02-13 15:07:37 +0100 |
|---|---|---|
| committer | Thijs Schreijer <thijs@thijsschreijer.nl> | 2026-02-13 15:07:37 +0100 |
| commit | a5ffa54ee71c9819fc413fdf118774b1db21a1df (patch) | |
| tree | 4072ed7df7c89395386074acfd45f8e47e59c8a6 | |
| parent | f6f0c77995fcd62863a7f24cbb407a68d2277759 (diff) | |
| download | luasystem-a5ffa54ee71c9819fc413fdf118774b1db21a1df.tar.gz luasystem-a5ffa54ee71c9819fc413fdf118774b1db21a1df.tar.bz2 luasystem-a5ffa54ee71c9819fc413fdf118774b1db21a1df.zip | |
align error handling
| -rw-r--r-- | spec/02-random_spec.lua | 27 | ||||
| -rw-r--r-- | src/random.c | 24 |
2 files changed, 23 insertions, 28 deletions
diff --git a/spec/02-random_spec.lua b/spec/02-random_spec.lua index db5d5ce..7b2eea6 100644 --- a/spec/02-random_spec.lua +++ b/spec/02-random_spec.lua | |||
| @@ -155,24 +155,27 @@ describe("Random:", function() | |||
| 155 | end) | 155 | end) |
| 156 | 156 | ||
| 157 | 157 | ||
| 158 | it("returns nil and error for empty interval (m > n)", function() | 158 | it("throws for empty interval (m > n), like math.random", function() |
| 159 | local v, err = system.rnd(10, 5) | 159 | local ok_math, _ = pcall(math.random, 10, 5) |
| 160 | assert.is_falsy(v) | 160 | assert.is_falsy(ok_math, "math.random(10, 5) should error") |
| 161 | assert.are.equal("interval is empty", err) | 161 | local ok_rnd, _ = pcall(system.rnd, 10, 5) |
| 162 | assert.is_falsy(ok_rnd, "rnd(10, 5) should throw like math.random") | ||
| 162 | end) | 163 | end) |
| 163 | 164 | ||
| 164 | 165 | ||
| 165 | it("returns nil and error for invalid one-arg (m < 1, m ~= 0)", function() | 166 | it("throws for invalid one-arg (m < 1, m ~= 0), like math.random", function() |
| 166 | local v, err = system.rnd(-1) | 167 | local ok_math, _ = pcall(math.random, -1) |
| 167 | assert.is_falsy(v) | 168 | assert.is_falsy(ok_math, "math.random(-1) should error") |
| 168 | assert.are.equal("interval is empty", err) | 169 | local ok_rnd, _ = pcall(system.rnd, -1) |
| 170 | assert.is_falsy(ok_rnd, "rnd(-1) should throw like math.random") | ||
| 169 | end) | 171 | end) |
| 170 | 172 | ||
| 171 | 173 | ||
| 172 | it("returns nil and error for wrong number of arguments", function() | 174 | it("throws for wrong number of arguments, like math.random", function() |
| 173 | local v, err = system.rnd(1, 2, 3) | 175 | local ok_math, _ = pcall(math.random, 1, 2, 3) |
| 174 | assert.is_falsy(v) | 176 | assert.is_falsy(ok_math, "math.random(1, 2, 3) should error") |
| 175 | assert.are.equal("wrong number of arguments", err) | 177 | local ok_rnd, _ = pcall(system.rnd, 1, 2, 3) |
| 178 | assert.is_falsy(ok_rnd, "rnd(1, 2, 3) should throw like math.random") | ||
| 176 | end) | 179 | end) |
| 177 | 180 | ||
| 178 | end) | 181 | end) |
diff --git a/src/random.c b/src/random.c index 6b09a55..33a640a 100644 --- a/src/random.c +++ b/src/random.c | |||
| @@ -126,8 +126,10 @@ static int lua_get_random_bytes(lua_State* L) { | |||
| 126 | /* Read 8 bytes into *out; return 0 on success, 2 on error (nil + msg pushed). */ | 126 | /* Read 8 bytes into *out; return 0 on success, 2 on error (nil + msg pushed). */ |
| 127 | static int read_u64(lua_State *L, uint64_t *out) { | 127 | static int read_u64(lua_State *L, uint64_t *out) { |
| 128 | unsigned char buf[8]; | 128 | unsigned char buf[8]; |
| 129 | |||
| 129 | int ret = fill_random_bytes(L, buf, 8); | 130 | int ret = fill_random_bytes(L, buf, 8); |
| 130 | if (ret != 0) return ret; | 131 | if (ret != 0) return ret; |
| 132 | |||
| 131 | *out = (uint64_t)buf[0] | ((uint64_t)buf[1] << 8) | ((uint64_t)buf[2] << 16) | | 133 | *out = (uint64_t)buf[0] | ((uint64_t)buf[1] << 8) | ((uint64_t)buf[2] << 16) | |
| 132 | ((uint64_t)buf[3] << 24) | ((uint64_t)buf[4] << 32) | ((uint64_t)buf[5] << 40) | | 134 | ((uint64_t)buf[3] << 24) | ((uint64_t)buf[4] << 32) | ((uint64_t)buf[5] << 40) | |
| 133 | ((uint64_t)buf[6] << 48) | ((uint64_t)buf[7] << 56); | 135 | ((uint64_t)buf[6] << 48) | ((uint64_t)buf[7] << 56); |
| @@ -162,13 +164,11 @@ Random number mimicking Lua 5.4 math.random, using crypto-secure bytes. | |||
| 162 | - One arg 0: returns a full-range random integer (whole lua_Integer range). | 164 | - One arg 0: returns a full-range random integer (whole lua_Integer range). |
| 163 | - One arg m (m >= 1): returns an integer in [1, m] (inclusive). | 165 | - One arg m (m >= 1): returns an integer in [1, m] (inclusive). |
| 164 | - Two args m, n: returns an integer in [m, n] (inclusive). | 166 | - Two args m, n: returns an integer in [m, n] (inclusive). |
| 165 | On invalid arguments returns nil and an error message. | 167 | On invalid arguments throws an error (same as math.random). |
| 166 | @function rnd | 168 | @function rnd |
| 167 | @tparam[opt] int m upper bound (or 0 for full-range), or lower bound when used with n | 169 | @tparam[opt] int m upper bound (or 0 for full-range), or lower bound when used with n |
| 168 | @tparam[opt] int n upper bound (when used with m) | 170 | @tparam[opt] int n upper bound (when used with m) |
| 169 | @treturn[1] number|int float in [0,1) or integer in the requested range | 171 | @treturn number|int float in [0,1) or integer in the requested range |
| 170 | @treturn[2] nil | ||
| 171 | @treturn[2] string error message | ||
| 172 | */ | 172 | */ |
| 173 | static int lua_rnd(lua_State *L) { | 173 | static int lua_rnd(lua_State *L) { |
| 174 | int nargs = lua_gettop(L); | 174 | int nargs = lua_gettop(L); |
| @@ -210,9 +210,7 @@ static int lua_rnd(lua_State *L) { | |||
| 210 | return 1; | 210 | return 1; |
| 211 | } | 211 | } |
| 212 | if (m < 1) { | 212 | if (m < 1) { |
| 213 | lua_pushnil(L); | 213 | return luaL_error(L, "interval is empty"); |
| 214 | lua_pushstring(L, "interval is empty"); | ||
| 215 | return 2; | ||
| 216 | } | 214 | } |
| 217 | /* [1, m] -> range size m, values 0..m-1 then +1 */ | 215 | /* [1, m] -> range size m, values 0..m-1 then +1 */ |
| 218 | { | 216 | { |
| @@ -234,15 +232,11 @@ static int lua_rnd(lua_State *L) { | |||
| 234 | RND_INT low = RND_CHECKINT(L, 1); | 232 | RND_INT low = RND_CHECKINT(L, 1); |
| 235 | RND_INT up = RND_CHECKINT(L, 2); | 233 | RND_INT up = RND_CHECKINT(L, 2); |
| 236 | if (low > up) { | 234 | if (low > up) { |
| 237 | lua_pushnil(L); | 235 | return luaL_error(L, "interval is empty"); |
| 238 | lua_pushstring(L, "interval is empty"); | ||
| 239 | return 2; | ||
| 240 | } | 236 | } |
| 241 | #if LUA_VERSION_NUM >= 503 | 237 | #if LUA_VERSION_NUM >= 503 |
| 242 | if (low < 0 && up > 0 && (lua_Unsigned)(up - low) > (lua_Unsigned)LUA_MAXINTEGER) { | 238 | if (low < 0 && up > 0 && (lua_Unsigned)(up - low) > (lua_Unsigned)LUA_MAXINTEGER) { |
| 243 | lua_pushnil(L); | 239 | return luaL_error(L, "interval too large"); |
| 244 | lua_pushstring(L, "interval too large"); | ||
| 245 | return 2; | ||
| 246 | } | 240 | } |
| 247 | #endif | 241 | #endif |
| 248 | { | 242 | { |
| @@ -261,9 +255,7 @@ static int lua_rnd(lua_State *L) { | |||
| 261 | } | 255 | } |
| 262 | } | 256 | } |
| 263 | 257 | ||
| 264 | lua_pushnil(L); | 258 | return luaL_error(L, "wrong number of arguments"); |
| 265 | lua_pushliteral(L, "wrong number of arguments"); | ||
| 266 | return 2; | ||
| 267 | 259 | ||
| 268 | #undef RND_INT | 260 | #undef RND_INT |
| 269 | #undef RND_CHECKINT | 261 | #undef RND_CHECKINT |
