<commit_before>package vexprtest;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.testng.Assert.assertEquals;

import vexpressed.core.ExpressionCalculatorVisitor;
import vexpressed.core.ExpressionException;

import java.math.BigDecimal;

import org.testng.annotations.Test;

public class MathOperatorTest extends TestBase {

	@Test
	public void unarySign() {
		assertEquals(eval("-(-5)"), 5);
		// next case colides with custom operators
		assertThatThrownBy(() -> eval("--5)"))
			.isInstanceOf(ExpressionException.class)
			.hasMessageMatching("(?s)Expression parse failed at 1:0.*'--'.*");
		assertThatThrownBy(() -> eval("-'nono'"))
			.isInstanceOf(ExpressionException.class);
	}

	@Test
	public void arithmeticOperations() {
		assertEquals(eval("5. / 2"), new BigDecimal("2.5"));
		assertEquals(eval("1"), 1);
		assertEquals(eval("5 + 1"), 6);
		// any non-integer promotes the whole result to BigDecimal, also notice how scale is set
		assertEquals(eval("5 + 1."), new BigDecimal("6"));
		assertEquals(eval("5 + 1.0"), new BigDecimal("6.0"));
		assertEquals(eval("1 - 1.050"), new BigDecimal("-0.050"));
		assertEquals(eval("5 - 6"), -1);
		// integer division
		assertEquals(eval("5 / 2"), 2);
		assertEquals(eval("5 % 2"), 1);
		assertEquals(eval("5. % 2"), BigDecimal.ONE);
		assertEquals(eval("5.1 % 2.6"), new BigDecimal("2.5"));
		// floating point division
	}

	@Test
	public void integerOverflowReturnsBigDecimal() {
		assertThat(eval("2_000_000_000 + 2_000_000_000")).isEqualTo(new BigDecimal(4_000_000_000L));
		assertThat(eval(Integer.MAX_VALUE + " * " + Integer.MAX_VALUE))
			.isEqualTo(new BigDecimal(Integer.MAX_VALUE)
				.multiply(new BigDecimal(Integer.MAX_VALUE)));
		assertThat(eval("0 - " + Integer.MIN_VALUE))
			.isEqualTo(new BigDecimal(((long) Integer.MAX_VALUE) + 1));
	}

	@Test
	public void arithmeticScale() {
		assertEquals(eval("1 / 3"), 0); // integer result
		assertEquals(((BigDecimal) eval("1 / 3.")).scale(),
			ExpressionCalculatorVisitor.DEFAULT_MAX_RESULT_SCALE);<commit_msg>test case for overflow switching / operation into decimal mode<commit_after>package vexprtest;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.testng.Assert.assertEquals;

import vexpressed.core.ExpressionCalculatorVisitor;
import vexpressed.core.ExpressionException;

import java.math.BigDecimal;

import org.testng.annotations.Test;

public class MathOperatorTest extends TestBase {

	@Test
	public void unarySign() {
		assertEquals(eval("-(-5)"), 5);
		// next case colides with custom operators
		assertThatThrownBy(() -> eval("--5)"))
			.isInstanceOf(ExpressionException.class)
			.hasMessageMatching("(?s)Expression parse failed at 1:0.*'--'.*");
		assertThatThrownBy(() -> eval("-'nono'"))
			.isInstanceOf(ExpressionException.class);
	}

	@Test
	public void arithmeticOperations() {
		assertEquals(eval("5. / 2"), new BigDecimal("2.5"));
		assertEquals(eval("1"), 1);
		assertEquals(eval("5 + 1"), 6);
		// any non-integer promotes the whole result to BigDecimal, also notice how scale is set
		assertEquals(eval("5 + 1."), new BigDecimal("6"));
		assertEquals(eval("5 + 1.0"), new BigDecimal("6.0"));
		assertEquals(eval("1 - 1.050"), new BigDecimal("-0.050"));
		assertEquals(eval("5 - 6"), -1);
		// integer division
		assertEquals(eval("5 / 2"), 2);
		assertEquals(eval("5 % 2"), 1);
		assertEquals(eval("5. % 2"), BigDecimal.ONE);
		assertEquals(eval("5.1 % 2.6"), new BigDecimal("2.5"));
		// floating point division
	}

	@Test
	public void integerOverflowReturnsBigDecimal() {
		assertThat(eval("2_000_000_000 + 2_000_000_000")).isEqualTo(new BigDecimal(4_000_000_000L));
		assertThat(eval(Integer.MAX_VALUE + " * " + Integer.MAX_VALUE))
			.isEqualTo(new BigDecimal(Integer.MAX_VALUE)
				.multiply(new BigDecimal(Integer.MAX_VALUE)));
		assertThat(eval("0 - " + Integer.MIN_VALUE))
			.isEqualTo(new BigDecimal(((long) Integer.MAX_VALUE) + 1));

		// after overflow the same expression may change behaviour
		variableResolver = var -> 2000;
		assertThat(eval("(a+a)/(a+1)")).isEqualTo(1);
		assertThat(eval("(a+a)%(a+1)")).isEqualTo(1999);
		// overflow lets decimal math kick in
		variableResolver = var -> 2_000_000_000;
		assertThat(eval("(a+a)/(a+1)")).isEqualTo(new BigDecimal("2.000000")); // small precision
		assertThat(eval("(a+a)%(a+1)")).isEqualTo(new BigDecimal("1999999999"));
	}

	@Test
	public void arithmeticScale() {
		assertEquals(eval("1 / 3"), 0); // integer result
		assertEquals(((BigDecimal) eval("1 / 3.")).scale(),
			ExpressionCalculatorVisitor.DEFAULT_MAX_RESULT_SCALE);
{'fraction_non_alphanumeric': 0.16631400761743545, 'fraction_numerical': 0.04443504020313161, 'mean_word_length': 5.138961038961039, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 1, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3304877', 'n_tokens_mistral': 1730, 'n_tokens_neox': 1514, 'n_words': 313}