Merge pull request #17 from nuest/master

Add tests and CI integrations, add CoC
measurements_archive
Norwin 6 years ago committed by GitHub
commit 12f37006bd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -2,3 +2,7 @@
^\.Rproj\.user$
^CHANGES\.md$
^tools*$
^\.travis\.yml$
^appveyor\.yml$
^CONDUCT\.md$
^codecov\.yml$

@ -0,0 +1,24 @@
# R for travis: see documentation at https://docs.travis-ci.com/user/languages/r
language: R
sudo: false
cache: packages
r:
- release
- devel
r_github_packages:
- r-lib/covr
before_install:
- sudo add-apt-repository ppa:ubuntugis/ubuntugis-unstable --yes
- sudo apt-get --yes --force-yes update -qq
# units/udunits2 dependency:
- sudo apt-get install --yes libudunits2-dev
# sf dependencies:
- sudo apt-get install --yes libproj-dev libgeos-dev libgdal-dev
after_success:
- Rscript -e 'covr::codecov()'
#- Rscript -e 'lintr::lint_package()'

@ -0,0 +1,25 @@
# Contributor Code of Conduct
As contributors and maintainers of this project, we pledge to respect all people who
contribute through reporting issues, posting feature requests, updating documentation,
submitting pull requests or patches, and other activities.
We are committed to making participation in this project a harassment-free experience for
everyone, regardless of level of experience, gender, gender identity and expression,
sexual orientation, disability, personal appearance, body size, race, ethnicity, age, or religion.
Examples of unacceptable behavior by participants include the use of sexual language or
imagery, derogatory comments or personal attacks, trolling, public or private harassment,
insults, or other unprofessional conduct.
Project maintainers have the right and responsibility to remove, edit, or reject comments,
commits, code, wiki edits, issues, and other contributions that are not aligned to this
Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed
from the project team.
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by
opening an issue or contacting one or more of the project maintainers.
This Code of Conduct is adapted from the Contributor Covenant
(http:contributor-covenant.org), version 1.0.0, available at
http://contributor-covenant.org/version/1/0/0/

@ -1,7 +1,7 @@
Package: opensensmapr
Type: Package
Title: Work with Sensor Data from opensensemap.org in R
Version: 0.3.2
Version: 0.3.3
URL: http://github.com/noerw/opensensmapR
BugReports: http://github.com/noerw/opensensmapR/issues
Imports:
@ -17,9 +17,11 @@ Suggests:
knitr,
rmarkdown,
lubridate,
units
Author: Norwin Roosen
Maintainer: Norwin Roosen <bugs@nroo.de>
units,
testthat,
covr
Authors@R: c(person("Norwin", "Roosen", role = c("aut", "cre"), email = "bugs@nroo.de"),
person("Daniel", "Nuest", role = c("ctb"), email = "daniel.nuest@uni-muenster.de", comment = c(ORCID = "0000-0003-2392-6140")))
Description: Download data (environmental measurements, sensorstations) from the
API of open data sensor web platform 'opensensemap.org' for analysis in R.
This platform provides realtime data of more than 1000 low-cost sensor

@ -20,6 +20,7 @@ export(osem_as_sensebox)
export(osem_box)
export(osem_boxes)
export(osem_counts)
export(osem_endpoint)
export(osem_measurements)
export(osem_phenomena)
export(st_as_sf.osem_measurements)

@ -29,7 +29,7 @@ dplyr_class_wrapper = function(callback) {
#' the callstack. See https://stackoverflow.com/a/33108841
#'
#' @noRd
isNonInteractive = function () {
is_non_interactive = function () {
ff <- sapply(sys.calls(), function(f) as.character(f[1]))
any(ff %in% c("knit2html", "render")) || !interactive()
}

@ -4,12 +4,19 @@
# for CSV responses (get_measurements) the readr package is a hidden dependency
# ==============================================================================
#' Get the default openSenseMap API endpoint
#' @export
#' @return A character string with the HTTP URL of the openSenseMap API
osem_endpoint = function() {
'https://api.opensensemap.org'
}
get_boxes_ = function (..., endpoint) {
response = osem_request_(endpoint, path = c('boxes'), ...)
if (length(response) == 0) {
warning('no boxes found for this query')
return(response)
warning('no senseBoxes found for this query')
return(osem_as_sensebox(as.data.frame(response)))
}
# parse each list element as sensebox & combine them to a single data.frame
@ -17,7 +24,8 @@ get_boxes_ = function (..., endpoint) {
df = dplyr::bind_rows(boxesList)
df$exposure = df$exposure %>% as.factor()
df$model = df$model %>% as.factor()
df$grouptag = df$grouptag %>% as.factor()
if(!is.null(df$grouptag))
df$grouptag = df$grouptag %>% as.factor()
df
}
@ -52,7 +60,7 @@ get_stats_ = function (endpoint) {
}
osem_request_ = function (host, path, ..., type = 'parsed', progress) {
progress = if (progress && !isNonInteractive()) httr::progress() else NULL
progress = if (progress && !is_non_interactive()) httr::progress() else NULL
res = httr::GET(host, progress, path = path, query = list(...))
if (httr::http_error(res)) {

@ -19,7 +19,7 @@
#' @param phenomenon Only return boxes that measured the given phenomenon in the
#' time interval as specified through \code{date} or \code{from / to}
#' @param endpoint The URL of the openSenseMap API instance
#' @param progress Whether to print download progress information
#' @param progress Whether to print download progress information defaults to \code{TRUE}
#' @return A \code{sensebox data.frame} containing a box in each row
#'
#' @seealso \href{https://docs.opensensemap.org/#api-Measurements-findAllBoxes}{openSenseMap API documentation (web)}
@ -38,8 +38,8 @@
#'
osem_boxes = function (exposure = NA, model = NA, grouptag = NA,
date = NA, from = NA, to = NA, phenomenon = NA,
endpoint = 'https://api.opensensemap.org',
progress = T) {
endpoint = osem_endpoint(),
progress = TRUE) {
# error, if phenomenon, but no time given
if (!is.na(phenomenon) && is.na(date) && is.na(to) && is.na(from))
@ -87,7 +87,7 @@ osem_boxes = function (exposure = NA, model = NA, grouptag = NA,
#' # get a specific box by ID
#' b = osem_box('57000b8745fd40c8196ad04c')
#'
osem_box = function (boxId, endpoint = 'https://api.opensensemap.org') {
osem_box = function (boxId, endpoint = osem_endpoint()) {
get_box_(boxId, endpoint = endpoint)
}

@ -33,7 +33,8 @@ plot.sensebox = function (x, ..., mar = c(2,2,1,1)) {
print.sensebox = function(x, ...) {
important_columns = c('name', 'exposure', 'lastMeasurement', 'phenomena')
data = as.data.frame(x)
print(data[important_columns], ...)
available_columns = important_columns %in% names(data)
print(data[available_columns], ...)
invisible(x)
}
@ -106,7 +107,7 @@ mutate.sensebox = dplyr_class_wrapper(osem_as_sensebox)
#' @export
`[.sensebox` = function(x, i, ...) {
s = NextMethod('[')
mostattributes(s) = attributes(x)
mostattributes(s) = attributes(s)
s
}

@ -11,6 +11,6 @@
#'
#' @export
#' @seealso \href{https://docs.opensensemap.org/#api-Misc-getStatistics}{openSenseMap API documentation (web)}
osem_counts = function (endpoint = 'https://api.opensensemap.org') {
osem_counts = function(endpoint = osem_endpoint()) {
get_stats_(endpoint)
}

@ -18,7 +18,7 @@
#' @param exposure Filter sensors by their exposure ('indoor', 'outdoor', 'mobile')
#' @param from A \code{POSIXt} like object to select a time interval
#' @param to A \code{POSIXt} like object to select a time interval
#' @param columns Select specific column in the output (see oSeM documentation)
#' @param columns Select specific column in the output (see openSenseMap API documentation)
#' @param endpoint The URL of the openSenseMap API
#' @param progress Whether to print download progress information
#'
@ -36,7 +36,7 @@ osem_measurements = function (x, ...) UseMethod('osem_measurements')
#' @export
#' @examples
#' # get measurements from all boxes
#' osem_measurements('Windrichtung')
#' m1 = osem_measurements('Windrichtung')
#'
osem_measurements.default = function (x, ...) {
bbox = structure(c(-180, -90, 180, 90), class = 'bbox')
@ -50,16 +50,16 @@ osem_measurements.default = function (x, ...) {
#' @examples
#' # get measurements from sensors within a bounding box
#' bbox = structure(c(7, 51, 8, 52), class = 'bbox')
#' osem_measurements(bbox, 'Temperatur')
#' m2 = osem_measurements(bbox, 'Temperatur')
#'
#' points = sf::st_multipoint(matrix(c(7.5, 7.8, 51.7, 52), 2, 2))
#' bbox2 = sf::st_bbox(points)
#' osem_measurements(bbox2, 'Temperatur', exposure = 'outdoor')
#' m3 = osem_measurements(bbox2, 'Temperatur', exposure = 'outdoor')
#'
osem_measurements.bbox = function (x, phenomenon, exposure = NA,
from = NA, to = NA, columns = NA,
...,
endpoint = 'https://api.opensensemap.org',
endpoint = osem_endpoint(),
progress = T) {
bbox = x
environment() %>%
@ -79,12 +79,12 @@ osem_measurements.bbox = function (x, phenomenon, exposure = NA,
#'
#' # ...or a single box
#' b = osem_box('57000b8745fd40c8196ad04c')
#' osem_measurements(b, phenomenon = 'Temperatur')
#' m4 = osem_measurements(b, phenomenon = 'Temperatur')
#'
osem_measurements.sensebox = function (x, phenomenon, exposure = NA,
from = NA, to = NA, columns = NA,
...,
endpoint = 'https://api.opensensemap.org',
endpoint = osem_endpoint(),
progress = T) {
boxes = x
environment() %>%
@ -106,8 +106,10 @@ parse_get_measurements_params = function (params) {
if (is.null(params$phenomenon) | is.na(params$phenomenon))
stop('Parameter "phenomenon" is required')
if (!is.na(params$from) && is.na(params$to))
stop('specify "from" only together with "to"')
if (
(!is.na(params$from) && is.na(params$to)) ||
(!is.na(params$to) && is.na(params$from))
) stop('specify "from" only together with "to"')
if (
(!is.null(params$bbox) && !is.null(params$boxes)) ||
@ -130,7 +132,7 @@ parse_get_measurements_params = function (params) {
}
if (!is.na(params$exposure)) query$exposure = params$exposure
if (!is.na(params$columns))
if (!any(is.na(params$columns)))
query$columns = paste(params$columns, collapse = ',')
else
query$columns = 'value,createdAt,lon,lat,sensorId,unit'
@ -160,7 +162,7 @@ paged_measurements_req = function (query) {
query$`to-date` = date_as_isostring(page$to)
res = do.call(get_measurements_, query)
if (query$progress && !isNonInteractive())
if (query$progress && !is_non_interactive())
cat(paste(query$`from-date`, query$`to-date`, sep = ' - '), '\n')
res

@ -43,7 +43,7 @@ mutate.osem_measurements = dplyr_class_wrapper(osem_as_measurements)
#' @export
`[.osem_measurements` = function(x, i, ...) {
s = NextMethod('[')
mostattributes(s) = attributes(x)
mostattributes(s) = attributes(s)
s
}

@ -1,9 +1,12 @@
# opensensmapr
This R package ingests data (environmental measurements, sensor stations) from
the API of opensensemap.org for analysis in R.
[![CRAN status](http://www.r-pkg.org/badges/version/opensensmapr)](https://cran.r-project.org/package=opensensmapr) [![Travis build status](https://travis-ci.org/noerw/opensensmapR.svg?branch=master)](https://travis-ci.org/noerw/opensensmapR) [![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/github/noerw/opensensmapR?branch=master&svg=true)](https://ci.appveyor.com/project/noerw/opensensmapR) [![Coverage status](https://codecov.io/gh/noerw/opensensmapR/branch/master/graph/badge.svg)](https://codecov.io/github/noerw/opensensmapR?branch=master)
This R package ingests data (environmental measurements, sensor stations) from the API of opensensemap.org for analysis in R.
The package aims to be compatible with sf and the tidyverse.
## Installation
Right now, the package is not on CRAN. To install it from GitHub, run:
```r
@ -12,9 +15,10 @@ devtools::install_github('noerw/opensensmapr')
```
## Usage
A verbose usage example is shown in the vignette [`osem-intro`](https://noerw.github.com/opensensmapR/inst/doc/osem-intro.html).
Each functions documentation can be viewed with `?<function-name>`. An overview
is given in `?opensensmapr`.
Each functions documentation can be viewed with `?<function-name>`.
An overview is given in `?opensensmapr`.
In short, the following pseudocode shows the main functions for data retrieval:
```r
@ -39,17 +43,23 @@ osem_counts()
Additionally there are some helpers: `summary.sensebox(), plot.sensebox(), st_as_sf.sensebox(), osem_as_sensebox(), [.sensebox(), filter.sensebox(), mutate.sensebox(), ...`.
## Changelog
This project adheres to semantic versioning, for changes in recent versions
please consult [CHANGES.md](CHANGES.md).
This project adheres to semantic versioning, for changes in recent versions please consult [CHANGES.md](CHANGES.md).
## FAQ
- *Whats up with that package name?* idk, the R people seem to [enjoy][1]
[dropping][2] [vovels][3] so.. Unfortunately I couldn't fit the naming
convention to drop an `y` in there.
- *Whats up with that package name?* idk, the R people seem to [enjoy][1] [dropping][2] [vovels][3] so..
Unfortunately I couldn't fit the naming convention to drop an `y` in there.
[1]: https://github.com/tidyverse/readr
[2]: https://github.com/tidyverse/dplyr
[3]: https://github.com/tidyverse/tidyr
## Development
Please note that this project is released with a [Contributor Code of Conduct](CONDUCT.md).
By participating in this project you agree to abide by its terms.
## License
GPL-2.0 - Norwin Roosen

@ -0,0 +1,45 @@
# DO NOT CHANGE the "init" and "install" sections below
# Download script file from GitHub
init:
ps: |
$ErrorActionPreference = "Stop"
Invoke-WebRequest http://raw.github.com/krlmlr/r-appveyor/master/scripts/appveyor-tool.ps1 -OutFile "..\appveyor-tool.ps1"
Import-Module '..\appveyor-tool.ps1'
install:
ps: Bootstrap
cache:
- C:\RLibrary
# Adapt as necessary starting from here
build_script:
- travis-tool.sh install_deps
test_script:
- travis-tool.sh run_tests
on_failure:
- 7z a failure.zip *.Rcheck\*
- appveyor PushArtifact failure.zip
artifacts:
- path: '*.Rcheck\**\*.log'
name: Logs
- path: '*.Rcheck\**\*.out'
name: Logs
- path: '*.Rcheck\**\*.fail'
name: Logs
- path: '*.Rcheck\**\*.Rout'
name: Logs
- path: '\*_*.tar.gz'
name: Bits
- path: '\*_*.zip'
name: Bits

@ -0,0 +1,12 @@
comment: false
coverage:
status:
project:
default:
target: auto
threshold: 1%
patch:
default:
target: auto
threshold: 1%

@ -91,3 +91,12 @@ openSenseMap API: \url{https://api.opensensemap.org/}
official openSenseMap API documentation: \url{https://docs.opensensemap.org/}
}
\author{
\strong{Maintainer}: Norwin Roosen \email{bugs@nroo.de}
Other contributors:
\itemize{
\item Daniel Nuest \email{daniel.nuest@uni-muenster.de} (0000-0003-2392-6140) [contributor]
}
}

@ -4,7 +4,7 @@
\alias{osem_box}
\title{Get a single senseBox by its ID}
\usage{
osem_box(boxId, endpoint = "https://api.opensensemap.org")
osem_box(boxId, endpoint = osem_endpoint())
}
\arguments{
\item{boxId}{A string containing a senseBox ID}

@ -5,8 +5,8 @@
\title{Get a set of senseBoxes from the openSenseMap}
\usage{
osem_boxes(exposure = NA, model = NA, grouptag = NA, date = NA,
from = NA, to = NA, phenomenon = NA,
endpoint = "https://api.opensensemap.org", progress = T)
from = NA, to = NA, phenomenon = NA, endpoint = osem_endpoint(),
progress = TRUE)
}
\arguments{
\item{exposure}{Only return boxes with the given exposure ('indoor', 'outdoor', 'mobile')}
@ -26,7 +26,7 @@ time interval as specified through \code{date} or \code{from / to}}
\item{endpoint}{The URL of the openSenseMap API instance}
\item{progress}{Whether to print download progress information}
\item{progress}{Whether to print download progress information defaults to \code{TRUE}}
}
\value{
A \code{sensebox data.frame} containing a box in each row

@ -4,7 +4,7 @@
\alias{osem_counts}
\title{Get count statistics of the openSenseMap Instance}
\usage{
osem_counts(endpoint = "https://api.opensensemap.org")
osem_counts(endpoint = osem_endpoint())
}
\arguments{
\item{endpoint}{The URL of the openSenseMap API}

@ -0,0 +1,14 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/api.R
\name{osem_endpoint}
\alias{osem_endpoint}
\title{Get the default openSenseMap API endpoint}
\usage{
osem_endpoint()
}
\value{
A character string with the HTTP URL of the openSenseMap API
}
\description{
Get the default openSenseMap API endpoint
}

@ -12,12 +12,11 @@ osem_measurements(x, ...)
\method{osem_measurements}{default}(x, ...)
\method{osem_measurements}{bbox}(x, phenomenon, exposure = NA, from = NA,
to = NA, columns = NA, ..., endpoint = "https://api.opensensemap.org",
progress = T)
to = NA, columns = NA, ..., endpoint = osem_endpoint(), progress = T)
\method{osem_measurements}{sensebox}(x, phenomenon, exposure = NA,
from = NA, to = NA, columns = NA, ...,
endpoint = "https://api.opensensemap.org", progress = T)
from = NA, to = NA, columns = NA, ..., endpoint = osem_endpoint(),
progress = T)
}
\arguments{
\item{x}{Depending on the method, either
@ -38,7 +37,7 @@ osem_measurements(x, ...)
\item{to}{A \code{POSIXt} like object to select a time interval}
\item{columns}{Select specific column in the output (see oSeM documentation)}
\item{columns}{Select specific column in the output (see openSenseMap API documentation)}
\item{endpoint}{The URL of the openSenseMap API}
@ -64,15 +63,15 @@ a bounding box spanning the whole world.
\examples{
# get measurements from all boxes
osem_measurements('Windrichtung')
m1 = osem_measurements('Windrichtung')
# get measurements from sensors within a bounding box
bbox = structure(c(7, 51, 8, 52), class = 'bbox')
osem_measurements(bbox, 'Temperatur')
m2 = osem_measurements(bbox, 'Temperatur')
points = sf::st_multipoint(matrix(c(7.5, 7.8, 51.7, 52), 2, 2))
bbox2 = sf::st_bbox(points)
osem_measurements(bbox2, 'Temperatur', exposure = 'outdoor')
m3 = osem_measurements(bbox2, 'Temperatur', exposure = 'outdoor')
# get measurements from a set of boxes
b = osem_boxes(grouptag = 'ifgi')
@ -80,7 +79,7 @@ osem_measurements(b, phenomenon = 'Temperatur')
# ...or a single box
b = osem_box('57000b8745fd40c8196ad04c')
osem_measurements(b, phenomenon = 'Temperatur')
m4 = osem_measurements(b, phenomenon = 'Temperatur')
}
\seealso{

@ -0,0 +1,5 @@
library("testthat")
library("opensensmapr")
library("sf")
test_check("opensensmapr")

@ -0,0 +1,31 @@
context("box")
check_api <- function() {
skip_on_cran()
code <- NA
try(code <- httr::status_code(httr::GET(osem_endpoint())))
if (is.na(code)) skip("API not available")
}
try({
boxes <- osem_boxes()
})
test_that("a single box can be retrieved by ID", {
check_api()
box <- osem_box(boxes$X_id[[1]])
expect_true("sensebox" %in% class(box))
expect_true("data.frame" %in% class(box))
expect_true(nrow(box) == 1)
expect_true(box$X_id == boxes$X_id[[1]])
})
test_that("[.sensebox maintains attributes", {
check_api()
expect_true(all(attributes(boxes[1:nrow(boxes), ]) %in% attributes(boxes)))
})

@ -0,0 +1,112 @@
context("boxes")
check_api <- function() {
skip_on_cran()
code <- NA
try(code <- httr::status_code(httr::GET(osem_endpoint())))
if (is.na(code)) skip("API not available")
}
test_that("a list of all boxes can be retrieved and returns a sensebox data.frame", {
check_api()
boxes <- osem_boxes()
expect_true(is.data.frame(boxes))
expect_true(is.factor(boxes$model))
expect_true(is.character(boxes$name))
expect_length(names(boxes), 14)
expect_true(any("sensebox" %in% class(boxes)))
})
test_that("both from and to are required when requesting boxes, error otherwise", {
expect_error(osem_boxes(from = as.POSIXct("2017-01-01")), "must be used together")
expect_error(osem_boxes(to = as.POSIXct("2017-01-01")), "must be used together")
})
test_that("a list of boxes with exposure filter returns only the requested exposure", {
check_api()
boxes <- osem_boxes(exposure = "mobile")
expect_true(all(boxes$exposure == "mobile"))
})
test_that("a list of boxes with model filter returns only the requested model", {
check_api()
boxes <- osem_boxes(model = "homeWifi")
expect_true(all(boxes$model == "homeWifi"))
})
test_that("box query can combine exposure and model filter", {
check_api()
boxes <- osem_boxes(exposure = "mobile", model = "homeWifi")
expect_true(all(boxes$model == "homeWifi"))
expect_true(all(boxes$exposure == "mobile"))
})
test_that("a list of boxes with grouptype returns only boxes of that group", {
check_api()
boxes <- osem_boxes(grouptag = "codeformuenster")
expect_true(all(boxes$grouptag == "codeformuenster"))
})
test_that("endpoint can be (mis)configured", {
check_api()
expect_error(osem_boxes(endpoint = "http://not.the.opensensemap.org"), "resolve host")
})
test_that("a response with no matches returns empty sensebox data.frame and a warning", {
check_api()
suppressWarnings(boxes <- osem_boxes(grouptag = "does_not_exist"))
expect_true(is.data.frame(boxes))
expect_true(any("sensebox" %in% class(boxes)))
})
test_that("a response with no matches gives a warning", {
check_api()
expect_warning(osem_boxes(grouptag = "does_not_exist"), "no senseBoxes found")
})
test_that("data.frame can be converted to sensebox data.frame", {
df <- osem_as_sensebox(data.frame(c(1,2), c("a", "b")))
expect_equal(class(df), c("sensebox", "data.frame"))
})
test_that("boxes can be converted to sf object", {
check_api()
boxes <- osem_boxes()
boxes_sf <- sf::st_as_sf(boxes)
expect_true(all(sf::st_is_simple(boxes_sf)))
expect_true("sf" %in% class(boxes_sf))
})
test_that("boxes converted to sf object keep all attributes", {
check_api()
boxes <- osem_boxes()
boxes_sf <- sf::st_as_sf(boxes)
# coord columns get removed!
cols <- names(boxes)[!names(boxes) %in% c('lon', 'lat')]
expect_true(all(cols %in% names(boxes_sf)))
expect_true("sensebox" %in% class(boxes_sf))
})
test_that("box retrieval does not give progress information in non-interactive mode", {
check_api()
if (!opensensmapr:::is_non_interactive()) skip("interactive session")
out <- capture.output(b <- osem_boxes())
expect_length(out, 0)
})

@ -0,0 +1,19 @@
context("counts")
check_api <- function() {
skip_on_cran()
code <- NA
try(code <- httr::status_code(httr::GET(osem_endpoint())))
if (is.na(code)) skip("API not available")
}
test_that("counts can be retrieved as a list of numbers", {
check_api()
counts <- osem_counts()
expect_true(is.list(counts))
expect_true(is.numeric(unlist(counts)))
expect_length(counts, 3)
})

@ -0,0 +1,121 @@
context("measurements")
check_api <- function() {
skip_on_cran()
code <- NA
try(code <- httr::status_code(httr::GET(osem_endpoint())))
if (is.na(code)) skip("API not available")
}
try({
boxes <- osem_boxes()
})
test_that("measurements can be retrieved for a phenomenon", {
check_api()
measurements <- osem_measurements(x = "Windgeschwindigkeit")
expect_true(is.data.frame(measurements))
expect_true("osem_measurements" %in% class(measurements))
})
test_that("measurement retrieval does not give progress information in non-interactive mode", {
check_api()
if (!opensensmapr:::is_non_interactive()) skip("interactive session")
out <- capture.output(measurements <- osem_measurements(x = "Licht"))
expect_length(out, 0)
})
test_that("a response with no matching senseBoxes gives an error", {
check_api()
expect_error(osem_measurements(x = "Windgeschwindigkeit", exposure = "indoor"), "No senseBoxes found")
})
test_that("data.frame can be converted to measurements data.frame", {
df <- osem_as_measurements(data.frame(c(1,2), c("a", "b")))
expect_equal(class(df), c("osem_measurements", "data.frame"))
})
test_that("columns can be specified for phenomena", {
check_api()
cols <- c("value", "boxId", "boxName")
measurements <- osem_measurements(x = "Windgeschwindigkeit", columns = cols)
expect_equal(names(measurements), cols)
})
test_that("measurements can be retrieved for a phenomenon and exposure", {
check_api()
measurements <- osem_measurements(x = "Temperatur", exposure = "unknown",
columns = c("value", "boxId", "boxName"))
expect_equal(nrow(measurements), 0)
})
test_that("measurements of specific boxes can be retrieved for one phenomenon and returns a measurements data.frame", {
check_api()
# fix for subsetting
class(boxes) <- c("data.frame")
three_boxes <- boxes[1:3,]
class(boxes) <- c("sensebox", "data.frame")
three_boxes <- osem_as_sensebox(three_boxes)
phens <- names(osem_phenomena(three_boxes))
measurements <- osem_measurements(x = three_boxes, phenomenon = phens[[1]])
expect_true(is.data.frame(measurements))
expect_true("osem_measurements" %in% class(measurements))
})
test_that("measurements can be retrieved for a bounding box", {
check_api()
sfc <- sf::st_sfc(sf::st_linestring(x = matrix(data = c(7, 8, 50, 51), ncol = 2)), crs = 4326)
bbox <- sf::st_bbox(sfc)
measurements <- osem_measurements(x = bbox, phenomenon = "Windrichtung")
expect_true(all(unique(measurements$lat) > 50))
expect_true(all(unique(measurements$lat) < 51))
expect_true(all(unique(measurements$lon) < 8))
expect_true(all(unique(measurements$lon) > 7))
})
test_that("measurements can be retrieved for a time period", {
check_api()
from_date <- as.POSIXct("2018-01-01 12:00:00")
to_date <- as.POSIXct("2018-01-01 13:00:00")
measurements <- osem_measurements(x = "Temperature", from = from_date, to = to_date)
expect_true(all(measurements$createdAt < to_date))
expect_true(all(measurements$createdAt > from_date))
})
test_that("measurements can be retrieved for a time period > 31 days", {
check_api()
from_date <- as.POSIXct("2017-11-01 12:00:00")
to_date <- as.POSIXct("2018-01-01 13:00:00")
measurements <- osem_measurements(x = "Windrichtung", from = from_date, to = to_date)
expect_true(all(measurements$createdAt < to_date))
expect_true(all(measurements$createdAt > from_date))
})
test_that("both from and to are required when requesting measurements, error otherwise", {
expect_error(osem_measurements(x = "Temperature", from = as.POSIXct("2017-01-01")), "only together with")
expect_error(osem_measurements(x = "Temperature", to = as.POSIXct("2017-01-01")), "only together with")
})
test_that("[.osem_measurements maintains attributes", {
check_api()
sfc <- sf::st_sfc(sf::st_linestring(x = matrix(data = c(7, 8, 50, 51), ncol = 2)), crs = 4326)
bbox <- sf::st_bbox(sfc)
m <- osem_measurements(x = bbox, phenomenon = "Windrichtung")
expect_true(all(attributes(m[1:nrow(m), ]) %in% attributes(m)))
})

@ -0,0 +1,40 @@
context("phenomena")
check_api <- function() {
skip_on_cran()
code <- NA
try(code <- httr::status_code(httr::GET(osem_endpoint())))
if (is.na(code)) skip("API not available")
}
try({
boxes <- osem_boxes()
all_phen <- unique(unlist(boxes$phenomena))
})
test_that("phenomena from boxes is a list of counts", {
check_api()
phenomena <- osem_phenomena(boxes)
expect_true(is.numeric(unlist(phenomena)))
expect_true(is.list(phenomena))
})
test_that("phenomena from boxes has all phenomena", {
check_api()
phenomena <- osem_phenomena(boxes)
expect_true(all(all_phen %in% names(phenomena)))
expect_true(all(names(phenomena) %in% all_phen))
})
test_that("phenomena from a not sensebox data.frame returns error", {
expect_error(osem_phenomena(list()), "no applicable method")
expect_error(osem_phenomena(data.frame()), "no applicable method")
boxes_df <- boxes
class(boxes_df) <- c("data.frame")
expect_error(osem_phenomena(boxes_df), "no applicable method")
})
Loading…
Cancel
Save