Merge pull request #17 from nuest/master
Add tests and CI integrations, add CoCmeasurements_archive
commit
12f37006bd
@ -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/
|
@ -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%
|
@ -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
|
||||
}
|
@ -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…
Reference in New Issue