Anirban166 / testComplexity

Asymptotic complexity testing framework
https://anirban166.github.io/testComplexity/
Other
36 stars 2 forks source link

Creating an expect function to capture output and throw an error for mismatch #35

Closed Anirban166 closed 4 years ago

Anirban166 commented 4 years ago

As suggested here, making a function to test the expected complexity (and thereby replace the call to stop("") in expect_time_complexity) is the aim of this issue.

From the list of expect_ functions in testthat/R/, expect_output is the most relevant one for our use (which internally uses _identical), as it tests for the captured output given by the object (first parameter, which would be the string returned by asymptoticTimeComplexityClass(df) in our case) ideally via a print() (which we are using) with the regular expression to match against (given by regexp). Test run with a succession and a fail case to observe how the error message pops up:
image

expect_identical would work well too: (including both of them together to see the contrast in the error message)
image

Both of them work fine and we could do without the need of reinventing the wheel, but I thought to create my expect_ function for a slightly better error message (+learning experience) and maybe the ability to test for two complexities against the object, to check for algorithms with misprediction between two continuous complexity classes (linear & loglinear for example), although I wouldn't have that in my package code, just to try out myself.

Anirban166 commented 4 years ago

image Seems okay
For two complexities (not preferred but still) we can just check if object is found in the vector of strings given by complexity.class for the ok parameter of expect like act$val %in% complexity.class, but then for ok if the condition has length > 1 only the first element will be used so thats not possible in this case.

Anirban166 commented 4 years ago

Regarding the functional flow, expect_complexity_class will be called by expect_time_complexity (again, a helper function) which in turn will be called by expect_x_time (where x denotes the complexity class) within the testthat test blocks. Example: (say x is linear for instance)

expect_complexity_class <- function(object, complexity.class)
{  actual.obj <- quasi_label(enquo(object), arg = "object")
   expect(
     actual.obj$val == complexity.class,
     sprintf("Complexity mismatch: Expected %s complexity, instead of the predicted %s complexity from %s.", complexity.class, actual.obj$val, actual.obj$lab)
  )
  invisible(actual.obj$val)
}
expect_time_complexity = function(complexity.class, ..., f)
{  f <- if(missing(f)) asymptoticTimings else f
   timings.df <- f(...)
   expect_complexity_class(asymptoticTimeComplexityClass(timings.df), complexity.class)
}
expect_linear_time = function(...)
{  expect_time_complexity("linear", ...)
}

The error message no longer uses a call to stop() which is good. Note that testthat is now an import instead of a suggest, since functions like quasi_label had to be obtained from testthat