Skip to content

Commit e93508f

Browse files
Gemini: more tests around NA_INTEGER64 sentinel value
1 parent 33e7c19 commit e93508f

1 file changed

Lines changed: 47 additions & 25 deletions

File tree

tests/testthat/test-ops64.R

Lines changed: 47 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -168,40 +168,62 @@ test_that("Minus and plus edge cases and 'rev'", {
168168
test_that("Overflow edge cases for arithmetic and summary functions", {
169169
max_val = lim.integer64()[2L]
170170
min_val = lim.integer64()[1L]
171+
half_min = as.integer64("-4611686018427387904") # -2^62
172+
half_max = as.integer64("4611686018427387904") # 2^62
171173

172174
overflow_warning = "NAs produced by integer64 overflow"
173175

174-
# Addition overflow
176+
# 1. C-level overflow (exceeds LLONG_MAX or below LLONG_MIN)
175177
expect_warning(expect_identical(max_val + 1L, NA_integer64_), overflow_warning)
176-
expect_warning(expect_identical(min_val + (-1L), NA_integer64_), overflow_warning)
177-
178-
# Subtraction overflow
179-
expect_warning(expect_identical(min_val - 1L, NA_integer64_), overflow_warning)
178+
expect_warning(expect_identical(min_val + (-2L), NA_integer64_), overflow_warning)
180179
expect_warning(expect_identical(max_val - (-1L), NA_integer64_), overflow_warning)
181-
182-
# Multiplication overflow
180+
expect_warning(expect_identical(min_val - 2L, NA_integer64_), overflow_warning)
183181
expect_warning(expect_identical(max_val * 2L, NA_integer64_), overflow_warning)
184182
expect_warning(expect_identical(min_val * 2L, NA_integer64_), overflow_warning)
185183
expect_warning(expect_identical(min_val * (-2L), NA_integer64_), overflow_warning)
186-
expect_identical(min_val * (-1L), max_val)
187-
188-
# sum() overflow
189-
expect_warning(expect_identical(sum(max_val, 1L), NA_integer64_), overflow_warning)
190-
expect_warning(expect_identical(sum(c(max_val, 1L)), NA_integer64_), overflow_warning)
191-
expect_warning(expect_identical(sum(c(min_val, -1L), na.rm = TRUE), NA_integer64_), overflow_warning)
184+
expect_warning(expect_identical(diff(c(max_val, min_val - 1L)), NA_integer64_), overflow_warning)
192185

193-
# prod() overflow
194-
expect_warning(expect_identical(prod(c(max_val, 2L)), NA_integer64_), overflow_warning)
195-
expect_warning(expect_identical(prod(c(min_val, 2L), na.rm = TRUE), NA_integer64_), overflow_warning)
196-
197-
# cumsum() overflow
198-
expect_warning(expect_identical(cumsum(c(max_val, 1L)), c(max_val, NA_integer64_)), overflow_warning)
199-
200-
# cumprod() overflow
201-
expect_warning(expect_identical(cumprod(c(max_val, 2L)), c(max_val, NA_integer64_)), overflow_warning)
202-
203-
# diff() overflow
204-
expect_warning(expect_identical(diff(c(max_val, min_val)), NA_integer64_), overflow_warning)
186+
# 2. NA_INTEGER64 sentinel collision: mathematical result is exactly LLONG_MIN (-2^63).
187+
# C-level __builtin_*_overflow does NOT overflow, but bit64 treats LLONG_MIN as NA.
188+
# These must produce NA_integer64_ with an overflow warning.
189+
expect_warning(expect_identical(min_val + (-1L), NA_integer64_), overflow_warning)
190+
expect_warning(expect_identical(half_min + half_min, NA_integer64_), overflow_warning)
191+
expect_warning(expect_identical(min_val - 1L, NA_integer64_), overflow_warning)
192+
expect_warning(expect_identical(as.integer64(-2L) * half_max, NA_integer64_), overflow_warning)
193+
expect_warning(expect_identical(as.integer64("-2147483648") * as.integer64("4294967296"), NA_integer64_), overflow_warning)
194+
expect_warning(expect_identical(diff(c(as.integer64(1L), min_val)), NA_integer64_), overflow_warning)
195+
expect_warning(expect_identical(sum(min_val, -1L), NA_integer64_), overflow_warning)
196+
expect_warning(expect_identical(sum(c(half_min, half_min)), NA_integer64_), overflow_warning)
197+
expect_warning(expect_identical(prod(as.integer64(-2L), half_max), NA_integer64_), overflow_warning)
198+
expect_warning(expect_identical(cumsum(c(min_val, -1L)), c(min_val, NA_integer64_)), overflow_warning)
199+
expect_warning(expect_identical(cumprod(c(as.integer64(-2L), half_max)), c(as.integer64(-2L), NA_integer64_)), overflow_warning)
200+
201+
# 3. Boundary cases that are exactly on the representable range [-2^63 + 1, 2^63 - 1]
202+
# These must NOT overflow or warn.
203+
expect_identical(min_val + 0L, min_val)
204+
expect_identical(min_val + 1L, as.integer64("-9223372036854775806"))
205+
expect_identical(half_min + (half_min + 1L), min_val)
206+
expect_identical(min_val - 0L, min_val)
207+
expect_identical(max_val - 0L, max_val)
208+
expect_identical(min_val * 1L, min_val)
209+
expect_identical(min_val * (-1L), max_val)
210+
expect_identical(max_val * (-1L), min_val)
211+
expect_identical(sum(min_val, 0L), min_val)
212+
expect_identical(prod(min_val, 1L), min_val)
213+
214+
# 4. NA propagation: when NA_INTEGER64 is an input, it should return NA without warning
215+
expect_no_warning(expect_identical(NA_integer64_ + 1L, NA_integer64_))
216+
expect_no_warning(expect_identical(1L + NA_integer64_, NA_integer64_))
217+
expect_no_warning(expect_identical(NA_integer64_ - 1L, NA_integer64_))
218+
expect_no_warning(expect_identical(1L - NA_integer64_, NA_integer64_))
219+
expect_no_warning(expect_identical(NA_integer64_ * 2L, NA_integer64_))
220+
expect_no_warning(expect_identical(2L * NA_integer64_, NA_integer64_))
221+
expect_no_warning(expect_identical(sum(NA_integer64_), NA_integer64_))
222+
expect_no_warning(expect_identical(prod(NA_integer64_), NA_integer64_))
223+
expect_no_warning(expect_identical(cumsum(c(NA_integer64_, 1L)), c(NA_integer64_, NA_integer64_)))
224+
expect_no_warning(expect_identical(cumprod(c(NA_integer64_, 1L)), c(NA_integer64_, NA_integer64_)))
225+
expect_no_warning(expect_identical(diff(c(NA_integer64_, as.integer64(1L))), NA_integer64_))
226+
expect_no_warning(expect_identical(diff(c(as.integer64(1L), NA_integer64_)), NA_integer64_))
205227
})
206228

207229
test_that("Logical operators", {

0 commit comments

Comments
 (0)