From 4539d73f5c0133efe42f02f4680ead580f2fd9f3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 31 Oct 2026 06:34:39 +0000 Subject: [PATCH 1/3] Add testthat coverage and contributor guidance Co-authored-by: asgr <5617132+asgr@users.noreply.github.com> --- .github/workflows/main.yml | 2 +- AGENTS.md | 24 ++++++++++++++++ DESCRIPTION | 3 +- tests/testthat.R | 4 +++ tests/testthat/test-coordinate-conversions.R | 28 +++++++++++++++++++ tests/testthat/test-coordinate-matching.R | 29 ++++++++++++++++++++ tests/testthat/test-cosmology.R | 14 ++++++++++ tests/testthat/test-sky-area.R | 18 ++++++++++++ tests/testthat/test-spherical-coordinates.R | 13 +++++++++ 9 files changed, 133 insertions(+), 2 deletions(-) create mode 100644 AGENTS.md create mode 100644 tests/testthat.R create mode 100644 tests/testthat/test-coordinate-conversions.R create mode 100644 tests/testthat/test-coordinate-matching.R create mode 100644 tests/testthat/test-cosmology.R create mode 100644 tests/testthat/test-sky-area.R create mode 100644 tests/testthat/test-spherical-coordinates.R diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index beab5bf..af0c77d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -43,7 +43,7 @@ jobs: - uses: r-lib/actions/setup-r-dependencies@v2 with: - extra-packages: any::rcmdcheck + extra-packages: any::rcmdcheck, any::testthat - uses: r-lib/actions/check-r-package@v2 with: diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..4f32b6b --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,24 @@ +# Working on `celestial` + +`celestial` is an R package of astronomical utilities. Most functionality is in +`R/`, package metadata is in `DESCRIPTION` and `NAMESPACE`, and user-facing +function documentation is in `man/`. The `src/` directory contains the +Rcpp-backed implementation and generated Rcpp bindings. + +## Tests and checks + +- Add package tests under `tests/testthat/`, with descriptive + `test-.R` filenames. Use `test_that()` and `expect_*()` from testthat. +- Run the focused suite with `Rscript -e 'devtools::test()'` and the package + check with `R CMD check .` when the required R dependencies are available. +- Keep tests deterministic; avoid network access and uncontrolled randomness. +- Keep `Suggests` and CI test dependencies in sync when adding test tools. + +## Changes + +- Preserve existing public function names, arguments, units, and return + structures unless a change explicitly calls for an API change. +- Update the relevant Rd documentation when changing a public function. +- Do not hand-edit `R/RcppExports.R` or `src/RcppExports.cpp`; regenerate these + bindings with Rcpp tooling when the C++ interface changes. +- Keep changes focused, and add tests for changed behavior and boundary cases. diff --git a/DESCRIPTION b/DESCRIPTION index 09883c6..4da723c 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -11,6 +11,7 @@ Description: Contains a number of common astronomy utility functions for cosmolo License: LGPL-3 LazyData: TRUE Depends: R (>= 3.00), RANN, NISTunits, pracma -Suggests: plotrix, igraph +Suggests: plotrix, igraph, testthat (>= 3.0.0) LinkingTo: Rcpp NeedsCompilation: yes +Config/testthat/edition: 3 diff --git a/tests/testthat.R b/tests/testthat.R new file mode 100644 index 0000000..520be89 --- /dev/null +++ b/tests/testthat.R @@ -0,0 +1,4 @@ +library(testthat) +library(celestial) + +test_check("celestial") diff --git a/tests/testthat/test-coordinate-conversions.R b/tests/testthat/test-coordinate-conversions.R new file mode 100644 index 0000000..66d701f --- /dev/null +++ b/tests/testthat/test-coordinate-conversions.R @@ -0,0 +1,28 @@ +test_that("decimal degrees convert to formatted DMS and HMS", { + expect_equal( + deg2dms(c(-27.345, 12.5), type = "cat", sep = ":"), + c("-27:20:42.00", "+12:30:00.00") + ) + expect_equal( + deg2hms(c(182.5, 0), type = "cat", sep = ":"), + c("12:10:00.00", "00:00:00.00") + ) +}) + +test_that("DMS values and strings convert back to decimal degrees", { + expect_equal( + dms2deg(d = c(27, 12), m = c(20, 30), s = c(42, 0), sign = c(-1, 1)), + c(-27.345, 12.5) + ) + expect_equal( + dms2deg(c("-27:20:42", "+12:30:00")), + c(-27.345, 12.5) + ) + expect_equal(hms2deg(c("12:10:00", "00:00:00")), c(182.5, 0)) +}) + +test_that("coordinate conversions reject values outside their domains", { + expect_error(deg2dms(91), "All deg values") + expect_error(dms2deg(d = 12, m = 60), "All m values") + expect_error(hms2deg(h = 25), "All h values") +}) diff --git a/tests/testthat/test-coordinate-matching.R b/tests/testthat/test-coordinate-matching.R new file mode 100644 index 0000000..14649e4 --- /dev/null +++ b/tests/testthat/test-coordinate-matching.R @@ -0,0 +1,29 @@ +test_that("coordinate matching returns matches and separations in requested units", { + reference <- rbind(c(10, 0), c(30, 0)) + comparison <- rbind(c(10 + 1 / 3600, 0), c(80, 0)) + + matches <- coordmatch(reference, comparison, rad = 2, radunit = "asec") + + expect_equal(matches$Nmatch, c(1, 0)) + expect_equal(matches$bestmatch$refID, 1) + expect_equal(matches$bestmatch$compareID, 1) + expect_equal(matches$bestmatch$sep, 1, tolerance = 1e-5) +}) + +test_that("single-coordinate matching chooses the nearest in-radius source", { + matches <- coordmatchsing( + RAref = 0, Decref = 0, + coordcompare = rbind(c(1, 0), c(0, 0)), + rad = 2, radunit = "deg" + ) + + expect_equal(matches$ID, c(2, 1)) + expect_equal(matches$bestmatch["compareID"], 2) + expect_equal(matches$bestmatch["sep"], 0, tolerance = 1e-10) +}) + +test_that("linked coordinate groups combine connected objects", { + groups <- group_links(rbind(c(10, 20), c(20, 30), c(40, 50))) + + expect_equal(groups, list(c(10, 20, 30), c(40, 50))) +}) diff --git a/tests/testthat/test-cosmology.R b/tests/testthat/test-cosmology.R new file mode 100644 index 0000000..14539e1 --- /dev/null +++ b/tests/testthat/test-cosmology.R @@ -0,0 +1,14 @@ +test_that("cosmological distances have expected identities and ordering", { + distances <- cosdist(z = c(0, 0.5, 1), H0 = 70, OmegaM = 0.3) + + expect_equal(distances$z, c(0, 0.5, 1)) + expect_equal(distances$CoDist[1], 0) + expect_true(all(diff(distances$CoDist) > 0)) + expect_equal(distances$LumDist, (1 + distances$z) * distances$CoDist) + expect_equal(distances$AngDist, distances$CoDist / (1 + distances$z)) +}) + +test_that("cosmological distance functions validate redshifts", { + expect_error(cosdist(z = -1), "z must be > -1") + expect_error(cosdist(z = Inf), "z must be finite") +}) diff --git a/tests/testthat/test-sky-area.R b/tests/testthat/test-sky-area.R new file mode 100644 index 0000000..6c2d336 --- /dev/null +++ b/tests/testthat/test-sky-area.R @@ -0,0 +1,18 @@ +test_that("sky area handles full-sky and unit conversions", { + full_sky <- skyarea(long = c(0, 360), lat = c(-90, 90), outunit = "sr") + + expect_equal(unname(full_sky["area"]), 4 * pi, tolerance = 1e-10) + expect_equal(unname(full_sky["areafrac"]), 1) + + degrees <- skyarea(long = c(0, 10), lat = c(0, 10), outunit = "deg2") + steradians <- skyarea(long = c(0, 10), lat = c(0, 10), outunit = "sr") + expect_equal(unname(steradians["area"]), + unname(degrees["area"]) * (pi / 180)^2, + tolerance = 1e-10) +}) + +test_that("sky area rejects unsupported units and non-physical regions", { + expect_error(skyarea(inunit = "hour"), "inunit must be") + expect_error(skyarea(outunit = "degree"), "outunit must be") + expect_error(skyarea(long = c(10, 0)), "non-physical") +}) diff --git a/tests/testthat/test-spherical-coordinates.R b/tests/testthat/test-spherical-coordinates.R new file mode 100644 index 0000000..4c0c05c --- /dev/null +++ b/tests/testthat/test-spherical-coordinates.R @@ -0,0 +1,13 @@ +test_that("spherical and Cartesian coordinates round-trip", { + spherical <- cbind(long = c(0, 90, 180), lat = c(0, 30, -45), + radius = c(1, 2, 3)) + + cartesian <- sph2car(spherical, deg = TRUE) + expect_equal(car2sph(cartesian, deg = TRUE), spherical, tolerance = 1e-10) +}) + +test_that("equatorial and galactic coordinates round-trip", { + equatorial <- cbind(RA = c(0, 123.4, 359), Dec = c(-30, 0, 70)) + + expect_equal(gal2eq(eq2gal(equatorial)), equatorial, tolerance = 1e-10) +}) From ea6f2855eeb003439bde50f6178d07d187c37ed3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 31 Oct 2026 06:35:39 +0000 Subject: [PATCH 2/3] Ensure CI resolves testthat dependencies Co-authored-by: asgr <5617132+asgr@users.noreply.github.com> --- .github/workflows/main.yml | 1 + AGENTS.md | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index af0c77d..78d2fd1 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -44,6 +44,7 @@ jobs: - uses: r-lib/actions/setup-r-dependencies@v2 with: extra-packages: any::rcmdcheck, any::testthat + needs: check - uses: r-lib/actions/check-r-package@v2 with: diff --git a/AGENTS.md b/AGENTS.md index 4f32b6b..da6d859 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -9,7 +9,7 @@ Rcpp-backed implementation and generated Rcpp bindings. - Add package tests under `tests/testthat/`, with descriptive `test-.R` filenames. Use `test_that()` and `expect_*()` from testthat. -- Run the focused suite with `Rscript -e 'devtools::test()'` and the package +- Run the focused suite with `Rscript -e 'testthat::test_local()'` and the package check with `R CMD check .` when the required R dependencies are available. - Keep tests deterministic; avoid network access and uncontrolled randomness. - Keep `Suggests` and CI test dependencies in sync when adding test tools. From ac93fd37e202edc6642fb796c333e55a633ffd97 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 6 Nov 2026 04:14:32 +0000 Subject: [PATCH 3/3] Ignore names in coordinate match tests Co-authored-by: asgr <5617132+asgr@users.noreply.github.com> --- tests/testthat/test-coordinate-matching.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/testthat/test-coordinate-matching.R b/tests/testthat/test-coordinate-matching.R index 14649e4..5075e2a 100644 --- a/tests/testthat/test-coordinate-matching.R +++ b/tests/testthat/test-coordinate-matching.R @@ -18,8 +18,8 @@ test_that("single-coordinate matching chooses the nearest in-radius source", { ) expect_equal(matches$ID, c(2, 1)) - expect_equal(matches$bestmatch["compareID"], 2) - expect_equal(matches$bestmatch["sep"], 0, tolerance = 1e-10) + expect_equal(unname(matches$bestmatch["compareID"]), 2) + expect_equal(unname(matches$bestmatch["sep"]), 0, tolerance = 1e-10) }) test_that("linked coordinate groups combine connected objects", {