Rewrite plot tests using C interface #703

The Plot unit tests were reaching directly into the objects,
which meant the implementations couldn't include anything
we didn't want public. This was annoying, so I've changed it.
This required adding ncdplot_sample() and ncuplot_sample(),
which we should have had anyway.
This commit is contained in:
nick black 2020-06-12 00:13:01 -04:00
parent 4d9171aee1
commit 70183ee283
No known key found for this signature in database
GPG Key ID: 5F43400C21CBFACC
7 changed files with 107 additions and 69 deletions

View File

@ -13,6 +13,8 @@ rearrangements of Notcurses.
* `ncvisual_geom()`'s `ncblitter_e` argument has been replaced with a
`const struct ncvisual_options*`, so that `NCVISUAL_OPTIONS_NODEGRADE`
can be taken into account (the latter contains a `blitter_e` field).
* Added `ncuplot_sample()` and `ncdplot_sample()`, allowing retrieval of
sample data from `ncuplot`s and `ncdplot`s, respectively.
* 1.5.0 (2020-07-08)
* The various `bool`s of `struct notcurses_options` have been folded into

View File

@ -46,6 +46,10 @@ typedef struct ncplot_options {
**int ncdplot_set_sample(struct ncdplot* n, uint64_t x, double y);**
**int ncuplot_sample(const struct ncuplot* n, uint64_t x, uint64_t* y);**
**int ncdplot_sample(const struct ncdplot* n, uint64_t x, double* y);**
**void ncuplot_destroy(struct ncuplot* n);**
**void ncdplot_destroy(struct ncdplot* n);**

View File

@ -2894,6 +2894,8 @@ API int ncuplot_add_sample(struct ncuplot* n, uint64_t x, uint64_t y);
API int ncdplot_add_sample(struct ncdplot* n, uint64_t x, double y);
API int ncuplot_set_sample(struct ncuplot* n, uint64_t x, uint64_t y);
API int ncdplot_set_sample(struct ncdplot* n, uint64_t x, double y);
API int ncuplot_sample(const struct ncuplot* n, uint64_t x, uint64_t* y);
API int ncdplot_sample(const struct ncdplot* n, uint64_t x, double* y);
API void ncuplot_destroy(struct ncuplot* n);
API void ncdplot_destroy(struct ncdplot* n);

View File

@ -460,6 +460,8 @@ int ncuplot_add_sample(struct ncuplot* n, uint64_t x, uint64_t y);
int ncdplot_add_sample(struct ncdplot* n, uint64_t x, double y);
int ncuplot_set_sample(struct ncuplot* n, uint64_t x, uint64_t y);
int ncdplot_set_sample(struct ncdplot* n, uint64_t x, double y);
int ncuplot_sample(const struct ncuplot* n, uint64_t x, uint64_t* y);
int ncdplot_sample(const struct ncdplot* n, uint64_t x, double* y);
void ncuplot_destroy(struct ncuplot* n);
void ncdplot_destroy(struct ncdplot* n);
bool ncplane_set_scrolling(struct ncplane* n, bool scrollp);

View File

@ -55,6 +55,14 @@ auto ncdplot_set_sample(ncdplot* n, uint64_t x, double y) -> int {
return n->n.set_sample(x, y);
}
auto ncuplot_sample(const ncuplot* n, uint64_t x, uint64_t* y) -> int {
return n->n.sample(x, y);
}
auto ncdplot_sample(const ncdplot* n, uint64_t x, double* y) -> int {
return n->n.sample(x, y);
}
void ncdplot_destroy(ncdplot* n) {
if(n){
n->n.destroy();

View File

@ -98,7 +98,7 @@ class ncppplot {
free(slots);
}
int redraw_plot() {
auto redraw_plot() -> int {
ncplane_erase(ncp);
const int scale = bset->width;
int dimy, dimx;
@ -250,7 +250,7 @@ class ncppplot {
// x window, the x window is advanced to include x, and values passing beyond
// the window are lost. The first call will place the initial window. The plot
// will be redrawn, but notcurses_render() is not called.
int add_sample(uint64_t x, T y) {
auto add_sample(uint64_t x, T y) -> int {
if(window_slide(x)){
return -1;
}
@ -261,7 +261,7 @@ class ncppplot {
return redraw_plot();
}
int set_sample(uint64_t x, T y) {
auto set_sample(uint64_t x, T y) -> int {
if(window_slide(x)){
return -1;
}
@ -272,11 +272,21 @@ class ncppplot {
return redraw_plot();
}
auto sample(int64_t x, T* y) const -> int {
if(x < slotx - (slotcount - 1)){ // x is behind window
return -1;
}else if(x > slotx){ // x is ahead of window
return -1;
}
*y = slots[x % slotcount];
return 0;
}
// if we're doing domain detection, update the domain to reflect the value we
// just set. if we're not, check the result against the known ranges, and
// return -1 if the value is outside of that range.
int update_domain(uint64_t x){
const uint64_t val = slots[x % slotcount];
auto update_domain(uint64_t x) -> int {
const T val = slots[x % slotcount];
if(detectdomain){
if(val > maxy){
maxy = val;
@ -299,7 +309,7 @@ class ncppplot {
// otherwise, the x is the newest sample. if it is obsoletes all existing slots,
// reset them, and write the new sample anywhere. otherwise, write it to the
// proper slot based on the current newest slot.
int window_slide(int64_t x){
auto window_slide(int64_t x) -> int {
if(x < slotx - (slotcount - 1)){ // x is behind window, won't be counted
return -1;
}else if(x <= slotx){ // x is within window, do nothing

View File

@ -1,5 +1,4 @@
#include "main.h"
#include "plot.h"
#include <cstring>
#include <iostream>
@ -47,84 +46,95 @@ TEST_CASE("Plot") {
SUBCASE("AugmentSamples5"){
ncplot_options popts{};
popts.rangex = 5;
ncppplot<uint64_t> p;
ncppplot<uint64_t>::create(&p, n_, &popts, 0, 10);
CHECK(0 == p.slots[0]);
CHECK(0 == p.add_sample((uint64_t)0, (uint64_t)1));
CHECK(1 == p.slots[0]);
CHECK(0 == p.add_sample((uint64_t)0, (uint64_t)1));
CHECK(2 == p.slots[0]);
CHECK(0 == p.slots[1]);
CHECK(0 == p.slots[2]);
CHECK(0 == p.add_sample((uint64_t)2, (uint64_t)3));
CHECK(3 == p.slots[2]);
CHECK(0 == p.set_sample((uint64_t)2, (uint64_t)3));
CHECK(3 == p.slots[2]);
CHECK(0 == p.slots[3]);
CHECK(0 == p.slots[4]);
CHECK(0 == p.add_sample((uint64_t)4, (uint64_t)6));
CHECK(6 == p.slots[4]);
CHECK(2 == p.slots[0]);
CHECK(4 == p.slotx);
p.destroy();
struct ncuplot* p = ncuplot_create(n_, &popts, 0, 10);
uint64_t y;
CHECK(0 == ncuplot_sample(p, 0, &y));
CHECK(0 == y);
CHECK(0 == ncuplot_add_sample(p, (uint64_t)0, (uint64_t)1));
CHECK(0 == ncuplot_sample(p, 0, &y));
CHECK(1 == y);
CHECK(0 == ncuplot_add_sample(p, (uint64_t)0, (uint64_t)1));
CHECK(0 == ncuplot_sample(p, 0, &y));
CHECK(2 == y);
CHECK(-1 == ncuplot_sample(p, 1, &y));
CHECK(-1 == ncuplot_sample(p, 2, &y));
CHECK(0 == ncuplot_add_sample(p, (uint64_t)2, (uint64_t)3));
CHECK(0 == ncuplot_sample(p, 2, &y));
CHECK(3 == y);
CHECK(0 == ncuplot_set_sample(p, (uint64_t)2, (uint64_t)3));
CHECK(0 == ncuplot_sample(p, 2, &y));
CHECK(3 == y);
CHECK(-1 == ncuplot_sample(p, 3, &y));
CHECK(-1 == ncuplot_sample(p, 4, &y));
CHECK(0 == ncuplot_add_sample(p, (uint64_t)4, (uint64_t)6));
CHECK(0 == ncuplot_sample(p, 4, &y));
CHECK(6 == y);
CHECK(0 == ncuplot_sample(p, 0, &y));
CHECK(2 == y);
//CHECK(4 == p->slotx);
ncuplot_destroy(p);
}
// 2-ary slot space with window movement
SUBCASE("AugmentCycle2"){
ncplot_options popts{};
popts.rangex = 2;
ncppplot<uint64_t> p;
ncppplot<uint64_t>::create(&p, n_, &popts, 0, 10);
CHECK(0 == p.slots[0]);
CHECK(0 == p.add_sample((uint64_t)0, (uint64_t)1));
CHECK(1 == p.slots[0]);
CHECK(0 == p.add_sample((uint64_t)0, (uint64_t)1));
CHECK(2 == p.slots[0]);
CHECK(0 == p.set_sample((uint64_t)1, (uint64_t)5));
CHECK(5 == p.slots[1]);
CHECK(0 == p.set_sample((uint64_t)2, (uint64_t)9));
CHECK(5 == p.slots[1]);
CHECK(9 == p.slots[0]);
CHECK(0 == p.add_sample((uint64_t)3, (uint64_t)4));
CHECK(9 == p.slots[0]);
CHECK(4 == p.slots[1]);
CHECK(3 == p.slotx);
CHECK(0 == p.add_sample((uint64_t)5, (uint64_t)1));
CHECK(1 == p.slots[0]);
CHECK(0 == p.slots[1]);
CHECK(5 == p.slotx);
p.destroy();
struct ncuplot* p = ncuplot_create(n_, &popts, 0, 10);
uint64_t y;
CHECK(0 == ncuplot_sample(p, 0, &y));
CHECK(0 == ncuplot_add_sample(p, (uint64_t)0, (uint64_t)1));
CHECK(0 == ncuplot_sample(p, 0, &y));
CHECK(1 == y);
CHECK(0 == ncuplot_add_sample(p, (uint64_t)0, (uint64_t)1));
CHECK(0 == ncuplot_sample(p, 0, &y));
CHECK(2 == y);
CHECK(0 == ncuplot_set_sample(p, (uint64_t)1, (uint64_t)5));
CHECK(0 == ncuplot_sample(p, 1, &y));
CHECK(5 == y);
CHECK(0 == ncuplot_set_sample(p, (uint64_t)2, (uint64_t)9));
CHECK(0 == ncuplot_sample(p, 1, &y));
CHECK(5 == y);
CHECK(-1 == ncuplot_sample(p, 0, &y));
CHECK(0 == ncuplot_add_sample(p, (uint64_t)3, (uint64_t)4));
CHECK(-1 == ncuplot_sample(p, 0, &y));
CHECK(-1 == ncuplot_sample(p, 1, &y));
//CHECK(3 == p->slotx);
CHECK(0 == ncuplot_add_sample(p, (uint64_t)5, (uint64_t)1));
CHECK(-1 == ncuplot_sample(p, 0, &y));
CHECK(-1 == ncuplot_sample(p, 1, &y));
//CHECK(5 == p.slotx);
ncuplot_destroy(p);
}
// augment past the window, ensuring everything gets zeroed
SUBCASE("AugmentLong"){
ncplot_options popts{};
popts.rangex = 5;
ncppplot<uint64_t> p;
ncppplot<uint64_t>::create(&p, n_, &popts, 0, 10);
for(int x = 0 ; x < 5 ; ++x){
CHECK(0 == p.slots[x]);
}
CHECK(0 == p.add_sample((uint64_t)4, (uint64_t)4));
for(int x = 0 ; x < 4 ; ++x){
CHECK(0 == p.slots[x]);
}
CHECK(4 == p.slots[4]);
CHECK(0 == p.add_sample((uint64_t)10, (uint64_t)5));
CHECK(5 == p.slots[0]);
for(int x = 1 ; x < 4 ; ++x){
CHECK(0 == p.slots[x]);
}
CHECK(0 == p.add_sample((uint64_t)24, (uint64_t)7));
CHECK(7 == p.slots[0]);
struct ncuplot* p = ncuplot_create(n_, &popts, 0, 10);
uint64_t y;
CHECK(0 == ncuplot_sample(p, 0, &y));
for(int x = 1 ; x < 5 ; ++x){
CHECK(0 == p.slots[x]);
CHECK(-1 == ncuplot_sample(p, x, &y));
}
CHECK(0 == p.add_sample((uint64_t)100, (uint64_t)0));
CHECK(0 == ncuplot_add_sample(p, (uint64_t)4, (uint64_t)4));
for(int x = 1 ; x < 4 ; ++x){
CHECK(0 == ncuplot_sample(p, x, &y));
}
CHECK(0 == ncuplot_sample(p, 4, &y));
CHECK(4 == y);
CHECK(0 == ncuplot_add_sample(p, (uint64_t)10, (uint64_t)5));
for(int x = 0 ; x < 4 ; ++x){
CHECK(-1 == ncuplot_sample(p, x, &y));
}
CHECK(0 == ncuplot_add_sample(p, (uint64_t)24, (uint64_t)7));
for(int x = 0 ; x < 5 ; ++x){
CHECK(0 == p.slots[x]);
CHECK(-1 == ncuplot_sample(p, x, &y));
}
p.destroy();
CHECK(0 == ncuplot_add_sample(p, (uint64_t)100, (uint64_t)0));
for(int x = 0 ; x < 5 ; ++x){
CHECK(-1 == ncuplot_sample(p, x, &y));
}
ncuplot_destroy(p);
}
// FIXME need some high-level rendering tests, one for each geometry