• Home
  • About
    • Anirban photo
    • About Me
    • Email
  • Blog Posts
    • Writings
    • Tags
  • Skill Set

Testers

30 Jul 2020

Reading time ~3 minutes

Emphasizing the testing functionality, some simple functions following the syntax of expect_xyz were created, enacting as cohesive components to achieve the task of testing a function for an expected complexity class, as per one of the base objectives.


Function Details : Parameters

  • expect_x_time
    • …: The arguments passed onto the time quantifier for the required function.
  • expect_time_complexity
    • complexity.class : A string denoting the expected complexity class.
    • …: Extracts the arguments from the above function when used in conjunction (or when the above function is called), otherwise requires them again if used separately (not meant to be).
    • f: A function to operate on the arguments given by the ellipsis, which by default is asymptoticTimings.
  • expect_complexity_class
    • object: Any chunk of code which returns a string to be compared against the expected string.
    • complexity.class: Same as above, its a string which is passed directly from expect_time_complexity based on x in expect_x_time, which denotes the expected complexity class.

Function Details : Implementation

To make it convenient for testing, the expect_x_time (where again x denotes the complexity class, such as linear, loglinear etc.) functions internally call expect_time_complexity which carries over the arguments supplied to asymptoticTimings by default and then tests for the expected complexity class with the data frame so returned passed onto asymptoticTimeComplexityClass, which in turn is passed as the first argument to expect_complexity_class along with the complexity class (as the second arg). The object is captured inside with quasi-labelling (utilizing quasi_label function from testthat) and quosure creation via the enquo() function. The captured object’s value is compared with the complexity class inside an expect function’s first argument, with the inclusion of an appropriate error message for the second argument. (failure_message) Put altogether, this helper function acts as the checking stone with an appropriate error message with a call to traceback shown in the case of test failure.

Function Details : Return value

expect_complexity_class invisibly returns the input object, so as to allow chaining of expectations or expect functions. If the expect() block test for ok fails then an error message governed by the second parameter of expect() is returned. expect_time_complexity and expect_x_time functions follow the same since they are tied together and link back to it.

Usage

Just pass the parameters as accepted in asymptoticTimings to the expect_x_time function of your choice:

test_that("PeakSegOptimal::PeakSegPDPA() function test", {
  # Passes:
  expect_loglinear_time({
  data.vec <- rpois(N, 1)
  PeakSegOptimal::PeakSegPDPA(data.vec, max.segments = 3L)}, data.sizes = 10^seq(1, 4, by = 0.5))
  # Fails:
  expect_quadratic_time({
  data.vec <- rpois(N, 1)
  PeakSegOptimal::PeakSegPDPA(data.vec, max.segments = 3L)}, data.sizes = 10^seq(1, 4, by = 0.5))
})

Code

  • expect_complexity_class
    expect_complexity_class <- function(object, complexity.class)
    { # Use quasi-labelling to capture value and label of passed object:
    actual.obj <- quasi_label(enquo(object), arg = "object")
    # Use the expect function:
    expect(
      # Set ok or success condition when the object returned matches with the complexity class supplied:
      actual.obj$val == complexity.class,
      # If failure of the above occurs, print a suitable error message regarding complexity message:
      sprintf("Complexity mismatch: Expected %s complexity, instead of the predicted %s complexity from %s.", complexity.class, actual.obj$val, actual.obj$lab)
    )
    # Return the object invisibly, to allow chaining of expectations/expect-functions:
    invisible(actual.obj$val)
    }
    
  • expect_time_complexity
    expect_time_complexity = function(complexity.class, ..., f)
    { # Use asymptoticTimings if function is not supplied:
    f <- if(missing(f)) asymptoticTimings else f
    # Collect the data frame returned by asymptoticTimings with parameters passed through the ellipsis:
    timings.df <- f(...)
    # Use the helper function to check/test for complexity class mismatch:
    expect_complexity_class(asymptoticTimeComplexityClass(timings.df), complexity.class)
    }
    
  • expect_linear_time
    expect_linear_time = function(...)
    { # Pass the arguments of this function to the time complexity testing helper function specifying the complexity class as linear:
    expect_time_complexity("linear", ...)
    }
    
  • expect_loglinear_time
    expect_loglinear_time = function(...)
    { # Pass the arguments of this function to the time complexity testing helper function specifying the complexity class as loglinear:
    expect_time_complexity("loglinear", ...)
    }
    
  • expect_quadratic_time
    expect_quadratic_time = function(...)
    { # Pass the arguments of this function to the time complexity testing helper function specifying the complexity class as quadratic:
    expect_time_complexity("quadratic", ...)
    }
    

    rxoygen-documented versions:

  • expect_complexity_class
  • expect_time_complexity
  • expect_linear_time
  • expect_loglinear_time
  • expect_quadratic_time
Anirban 07/30/2020


RPackageGSoC'20FunctionsCode Snippets Share Tweet +1