gt:     var softly = new SoftAssertions();
context: /*
   * C++ Community Plugin (cxx plugin)
   * Copyright (C) 2010-2022 SonarOpenCommunity
   * http://github.com/SonarOpenCommunity/sonar-cxx
   *
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of the GNU Lesser General Public
   * License as published by the Free Software Foundation; either
   * version 3 of the License, or (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   * Lesser General Public License for more details.
   *
   * You should have received a copy of the GNU Lesser General Public License
   * along with this program; if not, write to the Free Software Foundation,
   * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
   */
  package org.sonar.cxx.preprocessor;
  
  import com.sonar.sslr.api.Grammar;
  import java.io.File;
  import java.math.BigInteger;
  import org.assertj.core.api.SoftAssertions;
  import static org.junit.Assert.assertEquals;
  import static org.junit.Assert.assertFalse;
  import static org.junit.Assert.assertTrue;
  import org.junit.Test;
  import static org.mockito.ArgumentMatchers.anyList;
  import static org.mockito.ArgumentMatchers.anyString;
  import static org.mockito.Mockito.mock;
  import static org.mockito.Mockito.when;
  import org.sonar.cxx.squidbridge.SquidAstVisitorContext;
  
  public class ExpressionEvaluatorTest {
  
    static boolean eval(String constExpr, CxxPreprocessor pp) {
      return ExpressionEvaluator.eval(pp, constExpr);
    }
  
    static boolean eval(String constExpr) {
      return eval(constExpr, mock(CxxPreprocessor.class));
    }
  
    @Test
    public void bools() {
      assertTrue(eval("true"));
  
      assertFalse(eval("false"));
    }
  
    @Test
    public void numbers() {
      assertTrue(eval("1"));
      assertTrue(eval("0xAA"));
      assertTrue(eval("0XAA"));
      assertTrue(eval("1L"));
      assertTrue(eval("01L"));
      assertTrue(eval("1u"));
      assertTrue(eval("1000000000UL"));
      assertTrue(eval("0xFFFFFFFFFFFFFFFF"));
      assertTrue(eval("0xFFFFFFFFFFFFFFFFui64"));
      assertTrue(eval("0xFFFFFFFFFFFFFFFFLL"));
      assertTrue(eval("0xFFFFFFFFFFFFFFFFuLL"));
      assertTrue(eval("0xFFFFFFFFFFFFFFFFll"));
      assertTrue(eval("0xFFFFFFFFFFFFFFFFull"));
      assertTrue(eval("0xffffffffffffffffui64"));
      assertTrue(eval("0xffffffffffffffffi64"));
      assertTrue(eval("0x7FFFFFL"));
  
      assertFalse(eval("0"));
      assertFalse(eval("0x0"));
    }
  
    @Test
    public void characters() {
      assertTrue(eval("'1'"));
      assertTrue(eval("'a'"));
  
      assertFalse(eval("'\0'"));
    }
  
    @Test
    public void conditional_expression() {
      assertTrue(eval("1 ? 1 : 0"));
      assertTrue(eval("0 ? 0 : 1"));
  
      assertFalse(eval("1 ? 0 : 1"));
      assertFalse(eval("0 ? 1 : 0"));
  
      assertTrue(eval("1 ? : 0"));
      assertTrue(eval("0 ? : 1"));
    }
  
    @Test
    public void logical_or() {
      assertTrue(eval("1 || 0"));
      assertTrue(eval("0 || 1"));
      assertTrue(eval("1 || 1"));
      assertTrue(eval("0 || 0 || 1"));
  
      assertFalse(eval("0 || 0"));
      assertFalse(eval("0 || 0 || 0"));
    }
  
    @Test
    public void logical_and() {
      assertTrue(eval("1 && 1"));
      assertTrue(eval("1 && 1 && 1"));
  
      assertFalse(eval("1 && 0"));
      assertFalse(eval("0 && 1"));
      assertFalse(eval("0 && 0"));
      assertFalse(eval("1 && 1 && 0"));
    }
  
    @Test
    public void inclusive_or() {
      assertTrue(eval("1 | 0"));
      assertTrue(eval("0 | 1"));
      assertTrue(eval("1 | 1"));
      assertTrue(eval("0 | 0 | 1"));
  
      assertFalse(eval("0 | 0 | 0"));
    }
  
    @Test
    public void exclusive_or() {
      assertTrue(eval("1 ^ 0"));
      assertTrue(eval("0 ^ 1"));
      assertTrue(eval("0 ^ 1 ^ 0"));
  
      assertFalse(eval("0 ^ 0"));
      assertFalse(eval("0 ^ 1 ^ 1"));
    }
  
    @Test
    public void and_expr() {
      assertTrue(eval("1 & 1"));
      assertTrue(eval("2 & 2 & 2"));
  
      assertFalse(eval("0 & 1"));
      assertFalse(eval("1 & 0"));
      assertFalse(eval("0 & 0"));
      assertFalse(eval("2 & 4"));
      assertFalse(eval("1 & 1 & 4"));
    }
  
    @Test
    public void equality_expr() {
      assertTrue(eval("1 == 1"));
      assertTrue(eval("1 == true"));
      assertTrue(eval("true == true"));
      assertTrue(eval("true == 1"));
      assertTrue(eval("false == 0"));
      assertTrue(eval("0 == false"));
  
      assertTrue(eval("true != 2"));
      assertTrue(eval("false != 1"));
      assertTrue(eval("1 != 2"));
  
      assertFalse(eval("1 == 0"));
      assertFalse(eval("3 != 3"));
      assertFalse(eval("2 != 3 != 4"));
      assertFalse(eval("0 != 1 != true"));
  
      assertTrue(eval("1 == 1 == true"));
    }
  
    @Test
    public void relational_expr() {
      assertTrue(eval("0 < 1"));
      assertTrue(eval("0 <= 1"));
      assertTrue(eval("1 > 0"));
      assertTrue(eval("1 >= 0"));
      assertTrue(eval("0 < 0 < 2"));
  
      assertFalse(eval("3 < 2"));
      assertFalse(eval("3 <= 2"));
      assertFalse(eval("0 > 1"));
      assertFalse(eval("0 >= 1"));
      assertFalse(eval("0 < 1 < 1"));
  
      assertTrue(eval("2 > 1 > false"));
      assertTrue(eval("0 >= 0 >= false"));
      assertTrue(eval("0 <= 0  >= true"));
  
      assertFalse(eval("1 < 1 > false"));
      assertFalse(eval("0 >= 1 >= true"));
      assertFalse(eval("2 <= 2 <= false"));
    }
  
    @Test
    public void shift_expr() {
      assertTrue(eval("1 << 2"));
      assertTrue(eval("1 >> 0"));
  
      assertFalse(eval("0 << 1"));
      assertFalse(eval("0 >> 1"));
      assertFalse(eval("10 >> 1 >> 10"));
    }
  
    @Test
    public void additive_expr() {
      assertTrue(eval("1 + 1"));
      assertTrue(eval("2 - 1"));
      assertTrue(eval("3 - 3 + 2"));
  
      assertFalse(eval("0 + 0"));
      assertFalse(eval("1 - 1"));
      assertFalse(eval("3 - 2 - 1"));
    }
  
    @Test
    public void multiplicative_expr() {
      assertTrue(eval("1 * 2"));
      assertTrue(eval("1 / 1"));
      assertTrue(eval("1 % 2"));
  
      assertFalse(eval("0 * 1"));
      assertFalse(eval("0 / 1"));
      assertFalse(eval("1 % 1"));
      assertFalse(eval("1 * 1 * 0"));
    }
  
    @Test
    public void primary_expr() {
      assertTrue(eval("(1)"));
  
      assertFalse(eval("(0)"));
      assertFalse(eval("( 0 )"));
      assertFalse(eval("(1 || 0) && 0"));
    }
  
    @Test
    public void unary_expression() {
      assertTrue(eval("+1"));
      assertTrue(eval("-1"));
      assertTrue(eval("!0"));
      assertTrue(eval("~0"));
  
      assertFalse(eval("+0"));
      assertFalse(eval("-0"));
      assertFalse(eval("!1"));
      assertFalse(eval("~0xFFFFFFFFFFFFFFFF"));
    }
  
    @Test
    public void identifier_defined() {
      CxxPreprocessor pp = mock(CxxPreprocessor.class);
      when(pp.valueOf(anyString())).thenReturn("1");
      assertTrue(eval("LALA", pp));
    }
  
    @Test
    public void self_referential_identifier0() {
      CxxPreprocessor pp = mock(CxxPreprocessor.class);
      when(pp.valueOf("A")).thenReturn("A");
  
  