blob: f56a20381191433713e7ffd3900d17afb37bf996 [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2020 Stephan Wahlbrink and others.
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License 2.0 which is available at
# https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
# which is available at https://www.apache.org/licenses/LICENSE-2.0.
#
# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
#
# Contributors:
# Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
#=============================================================================*/
package org.eclipse.statet.rj.data.impl;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
import static org.eclipse.statet.rj.data.impl.AbstractRStore.DEFAULT_LONG_DATA_SEGMENT_LENGTH;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import org.eclipse.statet.jcommons.lang.NonNullByDefault;
import org.eclipse.statet.jcommons.lang.Nullable;
import org.eclipse.statet.rj.data.RIntegerStore;
import org.eclipse.statet.rj.data.RNumericStore;
import org.eclipse.statet.rj.data.RObject;
import org.eclipse.statet.rj.data.RStore;
@NonNullByDefault
public abstract class RNumericStoreTest extends AbstractRStoreTest {
static class NumCaseData extends CaseData {
final double[] values;
public NumCaseData(final String label, final double[] values, final boolean[] nas) {
super(label, nas);
assert (values.length == this.length);
assert (nas.length == this.length);
this.values= values;
}
public NumCaseData(final String label, final double[] values) {
super(label, values.length);
assert (values.length == this.length);
this.values= values;
}
}
protected static final List<NumCaseData> DEFAULT_DATA_SOURCES;
static {
final var datas= new ArrayList<NumCaseData>();
datas.add(new NumCaseData("empty", new double[0]));
datas.add(new NumCaseData("single-0", new double[] { 0 }));
datas.add(new NumCaseData("single-1", new double[] { 1 }));
datas.add(new NumCaseData("single-Min", new double[] { Double.MIN_VALUE }));
datas.add(new NumCaseData("single-Max", new double[] { Double.MAX_VALUE }));
datas.add(new NumCaseData("single-NA", new double[] { 0 }, new boolean[] { true }));
{ final double[] values= new double[0x1FF];
for (int i= 0; i < values.length; i++) {
values[i]= i - 0xFF;
}
datas.add(new NumCaseData("seq", values));
}
{ final double[] values= new double[0xFF];
final boolean[] nas= new boolean[values.length];
int i= 0;
values[i++]= 0;
values[i++]= -0;
values[i++]= +1;
values[i++]= -1;
values[i++]= Double.MIN_NORMAL;
values[i++]= Double.MIN_VALUE;
values[i++]= Double.MAX_VALUE;
values[i++]= Double.POSITIVE_INFINITY;
values[i++]= -Double.NEGATIVE_INFINITY;
values[i++]= Double.NaN;
nas[i++]= true;
datas.add(new NumCaseData("special", values, nas));
}
{ final Random rand= new Random(16857);
final double[] values= new double[100000];
for (int i= 0; i < values.length; i++) {
values[i]= rand.nextDouble();
}
datas.add(new NumCaseData("rand100000", values));
}
if (isBigDataEnabled(8)) {
final Random rand= new Random(46);
final double[] values= new double[DEFAULT_LONG_DATA_SEGMENT_LENGTH * 2 + 13];
for (int i= 0; i < values.length; i++) {
values[i]= rand.nextDouble();
}
datas.add(new NumCaseData("randMultiSeg", values));
}
DEFAULT_DATA_SOURCES= datas;
}
public RNumericStoreTest() {
}
public static List<NumCaseData> provideCaseDatas() {
return new ArrayList<>(DEFAULT_DATA_SOURCES);
}
protected abstract RNumericStore createStore(final NumCaseData data);
@ParameterizedTest
@MethodSource("provideCaseDatas")
public void getStoreType(final NumCaseData data) {
final RNumericStore store= createStore(data);
assertEquals(RStore.NUMERIC, store.getStoreType());
}
@ParameterizedTest
@MethodSource("provideCaseDatas")
public void getBaseVectorRClassName(final NumCaseData data) {
final RNumericStore store= createStore(data);
assertEquals(RObject.CLASSNAME_NUMERIC, store.getBaseVectorRClassName());
}
@ParameterizedTest
@MethodSource("provideCaseDatas")
public void length(final NumCaseData data) {
final RNumericStore store= createStore(data);
checkLength(data, store);
}
@ParameterizedTest
@MethodSource("provideCaseDatas")
public void isNA(final NumCaseData data) {
final RNumericStore store= createStore(data);
checkIsNA(data, store);
}
@ParameterizedTest
@MethodSource("provideCaseDatas")
public void isMissing(final NumCaseData data) {
final RNumericStore store= createStore(data);
for (int i= 0; i < data.length; i++) {
final int i0= i;
if (data.nas[i0]
|| Double.isNaN(data.values[i0])) {
assertTrue(store.isMissing(i0), storeDiffersAt(i0));
assertTrue(store.isMissing((long)i0), storeDiffersAt(i0));
}
else {
assertFalse(store.isMissing(i0), storeDiffersAt(i0));
assertFalse(store.isMissing((long)i0), storeDiffersAt(i0));
}
}
assertIndexOutOfBounds(data, store::isMissing, store::isMissing);
}
@ParameterizedTest
@MethodSource("provideCaseDatas")
public void isNaN(final NumCaseData data) {
final RNumericStore store= createStore(data);
for (int i= 0; i < data.length; i++) {
final int i0= i;
if (data.nas[i0]) {
assertFalse(store.isNaN(i0), storeDiffersAt(i0));
assertFalse(store.isNaN((long)i0), storeDiffersAt(i0));
}
else if (Double.isNaN(data.values[i0])) {
assertTrue(store.isNaN(i0), storeDiffersAt(i0));
assertTrue(store.isNaN((long)i0), storeDiffersAt(i0));
}
else {
assertFalse(store.isNaN(i0), storeDiffersAt(i0));
assertFalse(store.isNaN((long)i0), storeDiffersAt(i0));
}
}
assertIndexOutOfBounds(data, store::isMissing, store::isMissing);
}
@ParameterizedTest
@MethodSource("provideCaseDatas")
@SuppressWarnings("boxing")
public void getLogi(final NumCaseData data) {
final RNumericStore store= createStore(data);
for (int i= 0; i < data.length; i++) {
final int i0= i;
try {
if (data.nas[i0]) {
// undefined
}
else {
final Boolean expected= Boolean.valueOf(data.values[i0] != 0);
assertEquals(expected, store.getLogi(i0), storeDiffersAt(i0));
assertEquals(expected, store.getLogi((long)i0), storeDiffersAt(i0));
}
}
catch (final NumberFormatException e) {
fail(storeDiffersAt(i0).get(), e);
}
}
assertIndexOutOfBounds(data, store::getLogi, store::getLogi);
}
@ParameterizedTest
@MethodSource("provideCaseDatas")
public void getInt(final NumCaseData data) {
final RNumericStore store= createStore(data);
for (int i= 0; i < data.length; i++) {
final int i0= i;
try {
if (data.nas[i0]) {
// undefined
}
else if (data.values[i0] >= RIntegerStore.MIN_INT && data.values[i0] <= RIntegerStore.MAX_INT) {
final int expected= (int)data.values[i0];
assertEquals(expected, store.getInt(i0), storeDiffersAt(i0));
assertEquals(expected, store.getInt((long)i0), storeDiffersAt(i0));
}
else {
// ?
}
}
catch (final NumberFormatException e) {
fail(storeDiffersAt(i0).get(), e);
}
}
assertIndexOutOfBounds(data, store::getInt, store::getInt);
}
@ParameterizedTest
@MethodSource("provideCaseDatas")
public void getNum(final NumCaseData data) {
final RNumericStore store= createStore(data);
for (int i= 0; i < data.length; i++) {
final int i0= i;
if (data.nas[i0]) {
// undefined
}
else {
final double expected= data.values[i0];
assertEquals(expected, store.getNum(i0), storeDiffersAt(i0));
assertEquals(expected, store.getNum((long)i0), storeDiffersAt(i0));
}
}
assertIndexOutOfBounds(data, store::getNum, store::getNum);
}
@ParameterizedTest
@MethodSource("provideCaseDatas")
public void getCplx(final NumCaseData data) {
final RNumericStore store= createStore(data);
for (int i= 0; i < data.length; i++) {
final int i0= i;
if (data.nas[i0]) {
// undefined
}
else {
final double expectedRe= data.values[i0];
assertEquals(expectedRe, store.getCplxRe(i0), storeDiffersAt(i0));
assertEquals(expectedRe, store.getCplxRe((long)i0), storeDiffersAt(i0));
assertEquals(0, store.getCplxIm(i0), storeDiffersAt(i0));
assertEquals(0, store.getCplxIm((long)i0), storeDiffersAt(i0));
}
}
assertIndexOutOfBounds(data, store::getNum, store::getNum);
}
@ParameterizedTest
@MethodSource("provideCaseDatas")
public void getChar(final NumCaseData data) {
final RNumericStore store= createStore(data);
for (int i= 0; i < data.length; i++) {
final int i0= i;
if (data.nas[i0]) {
// undefined
}
else {
final String expected= Double.toString(data.values[i0]).replace("Infinity", "Inf");
assertEquals(expected, store.getChar(i0), storeDiffersAt(i0));
assertEquals(expected, store.getChar((long)i0), storeDiffersAt(i0));
}
}
assertIndexOutOfBounds(data, store::getChar, store::getChar);
}
@ParameterizedTest
@MethodSource("provideCaseDatas")
public void getRaw(final NumCaseData data) {
final RNumericStore store= createStore(data);
assertUnsupported(data, store::getRaw, store::getRaw);
}
@ParameterizedTest
@MethodSource("provideCaseDatas")
public void get(final NumCaseData data) {
final RNumericStore store= createStore(data);
for (int i= 0; i < data.length; i++) {
final int i0= i;
if (data.nas[i0]) {
assertNull(store.get(i0), storeDiffersAt(i0));
}
else {
final Double expected= Double.valueOf(data.values[i0]);
assertEquals(expected, store.get(i0), storeDiffersAt(i0));
assertEquals(expected, store.get((long)i0), storeDiffersAt(i0));
}
}
assertIndexOutOfBounds(data, store::get, store::get);
}
@ParameterizedTest
@MethodSource("provideCaseDatas")
public void toArray(final NumCaseData data) {
final RNumericStore store= createStore(data);
final @Nullable Double[] array= store.toArray();
assertEquals(data.values.length, array.length);
for (int i= 0; i < data.length; i++) {
final int i0= i;
if (data.nas[i0]) {
assertNull(array[i0], arrayDiffersAt(i0));
}
else {
final Double expected= Double.valueOf(data.values[i0]);
assertEquals(expected, array[i0], arrayDiffersAt(i0));
}
}
}
}