code: /*
   * Copyright (c) 2019 the Eclipse Milo Authors
   *
   * 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/
   *
   * SPDX-License-Identifier: EPL-2.0
   */
  
  package org.eclipse.milo.opcua.sdk.core;
  
  import java.util.Arrays;
  
  import org.eclipse.milo.opcua.stack.core.UaException;
  import org.eclipse.milo.opcua.stack.core.types.builtin.ByteString;
  import org.eclipse.milo.opcua.stack.core.types.builtin.Variant;
  import org.testng.annotations.DataProvider;
  import org.testng.annotations.Test;
  
  import static org.testng.Assert.assertEquals;
  import static org.testng.Assert.assertTrue;
  
  public class NumericRangeTest {
  
      @Test(dataProvider = "getArray1dRanges")
      public void testArray1d(String range, int[] expected) throws UaException {
          NumericRange nr = NumericRange.parse(range);
          Variant value = new Variant(array1d);
  
          Object result = NumericRange.readFromValueAtRange(value, nr);
  
          assertTrue(result instanceof int[]);
          assertTrue(Arrays.equals(expected, (int[]) result));
      }
  
      @Test(dataProvider = "getArray2dRanges")
      public void testArray2d(String range, int[][] expected) throws UaException {
          NumericRange nr = NumericRange.parse(range);
          Variant value = new Variant(array2d);
  
          Object result = NumericRange.readFromValueAtRange(value, nr);
  
          assertTrue(result instanceof int[][]);
          assertTrue(Arrays.deepEquals(expected, (int[][]) result));
      }
  
      @Test(dataProvider = "getArray3dRanges")
      public void testArray3d(String range, int[][][] expected) throws UaException {
          NumericRange nr = NumericRange.parse(range);
          Variant value = new Variant(array3d);
  
          Object result = NumericRange.readFromValueAtRange(value, nr);
  
          assertTrue(result instanceof int[][][]);
          assertTrue(Arrays.deepEquals(expected, (int[][][]) result));
      }
  
      @Test
      public void testArrayBeyondEnd() throws UaException {
          int[] array = new int[]{0, 1, 2, 3};
          NumericRange nr = NumericRange.parse("0:10");
          Variant value = new Variant(array);
  
          Object result = NumericRange.readFromValueAtRange(value, nr);
  
          assertTrue(result instanceof int[]);
          assertEquals(result, array);
      }
  
      @Test
      public void testString1d() throws UaException {
          NumericRange nr = NumericRange.parse("1:2");
          Variant value = new Variant("abcdef");
  
          Object result = NumericRange.readFromValueAtRange(value, nr);
  
          assertTrue(result instanceof String);
          assertTrue("bc".equals(result));
      }
  
      @Test
      public void testString2d_1() throws UaException {
          NumericRange nr = NumericRange.parse("0:1,3:4");
          Variant value = new Variant(new String[]{
              "abcdef",
              "ghijkl"
          });
  
          Object result = NumericRange.readFromValueAtRange(value, nr);
  
          assertTrue(result instanceof String[]);
          assertTrue(Arrays.deepEquals(new String[]{"de", "jk"}, (String[]) result));
      }
  
      @Test
      public void testString2d_2() throws UaException {
          NumericRange nr = NumericRange.parse("0:2,0:2");
          Variant value = new Variant(new String[]{
              "abcdef",
              "ghijkl",
              "mnopqr"
          });
  
          Object result = NumericRange.readFromValueAtRange(value, nr);
  
          assertTrue(result instanceof String[]);
          assertTrue(Arrays.deepEquals(new String[]{"abc", "ghi", "mno"}, (String[]) result));
      }
  
      @Test
      public void testStringBeyondEnd() throws UaException {
          String string = "abcdef";
          NumericRange nr = NumericRange.parse("0:10");
          Variant value = new Variant(string);
  
          Object result = NumericRange.readFromValueAtRange(value, nr);
  
          assertTrue(result instanceof String);
          assertEquals(result, string);
      }
  
      @Test
      public void testByteString1d() throws UaException {
          NumericRange nr = NumericRange.parse("1:2");
          Variant value = new Variant(new ByteString(new byte[]{1, 2, 3, 4}));
  
          Object result = NumericRange.readFromValueAtRange(value, nr);
  
          assertTrue(result instanceof ByteString);
          assertEquals(result, new ByteString(new byte[]{2, 3}));
      }
  
      @Test
      public void testByteString2d() throws UaException {
          NumericRange nr = NumericRange.parse("0:1,1:2");
          Variant value = new Variant(new ByteString[]{
              new ByteString(new byte[]{1, 2, 3, 4}),
              new ByteString(new byte[]{5, 6, 7, 8})
          });
  
          Object result = NumericRange.readFromValueAtRange(value, nr);
  
          assertTrue(result instanceof ByteString[]);
  
          ByteString[] expected = {
              new ByteString(new byte[]{2, 3}),
              new ByteString(new byte[]{6, 7})
          };
  
          assertTrue(Arrays.deepEquals((ByteString[]) result, expected));
      }
  
      @Test
      public void testByteStringBeyondEnd() throws UaException {
          ByteString byteString = new ByteString(new byte[]{1, 2, 3, 4});
          NumericRange nr = NumericRange.parse("0:10");
          Variant value = new Variant(byteString);
  
          Object result = NumericRange.readFromValueAtRange(value, nr);
  
          assertTrue(result instanceof ByteString);
          assertEquals(result, byteString);
      }
  
      @Test(dataProvider = "getInvalidRanges", expectedExceptions = UaException.class)
      public void testInvalidRange(String indexRange) throws UaException {
          NumericRange.parse(indexRange);
      }
  
  
      @Test
      public void testWrite1d() throws UaException {
          Variant current = new Variant(new int[]{0, 1, 2, 3});
          Variant update = new Variant(new int[]{2, 4});
          NumericRange range = NumericRange.parse("1:2");
  
          Object updated = NumericRange.writeToValueAtRange(current, update, range);
  
          assertTrue(updated instanceof int[]);
          assertTrue(Arrays.equals(
              (int[]) updated,
              new int[]{0, 2, 4, 3}
          ));
      }
  
      @Test
      public void testWriteString() throws UaException {
          Variant current = new Variant("abcdefg");
          Variant update = new Variant("ZzZzZ");
          NumericRange range = NumericRange.parse("1:5");
  
          Object updated = NumericRange.writeToValueAtRange(current, update, range);
  
          assertTrue(updated instanceof String);
          assertEquals(updated, "aZzZzZg");
      }
  
      @Test
      public void testWriteByteString() throws UaException {
          Variant current = new Variant(new ByteString(new byte[]{0, 1, 2, 3}));
          Variant update = new Variant(new ByteString(new byte[]{2, 4}));
          NumericRange range = NumericRange.parse("1:2");
  
          Object updated = NumericRange.writeToValueAtRange(current, update, range);
  
          assertTrue(updated instanceof ByteString);
          assertEquals(updated, new ByteString(new byte[]{0, 2, 4, 3}));
      }
  
      @DataProvider
      private static Object[][] getInvalidRanges() {
          return new Object[][]{
              {"0:0"},
              {"1:1"},
              {"-4:0"},
              {"0:-4"},
              {"3:1"},
              {"abc,def"},
              {"1:2,3:1"},
          };
      }
  
      private static final int[] array1d = new int[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
  
      @DataProvider
      private static Object[][] getArray1dRanges() {
          return new Object[][]{
              {"0:3", new int[]{0, 1, 2, 3}},
              {"4:9", new int[]{4, 5, 6, 7, 8, 9}},
              {"1:4", new int[]{1, 2, 3, 4}},
              {"5:8", new int[]{5, 6, 7, 8}},
              {"0:10", new int[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}},
              {"5:15", new int[]{5, 6, 7, 8, 9}},
              {"0", new int[]{0}},
              {"5", new int[]{5}},
              {"9", new int[]{9}}
          };
      }
  
  
      private static final int[][] array2d = new int[][]{
          {0, 1, 2, 3},
          {4, 5, 6, 7},
          {8, 9, 10, 11},
          {12, 13, 14, 15}
      };
  
      @DataProvider
      private static Object[][] getArray2dRanges() {
          return new Object[][]{
              {"0:1,0:1", new int[][]{{0, 1}, {4, 5}}},
              {"1:2,1:3", new int[][]{{5, 6, 7}, {9, 10, 11}}},
              {"2:5,2:5", new int[][]{{10, 11}, {14, 15}}},
              {"3,3", new int[][]{{15}}}
          };
      }
  
      private static final int[][][] array3d = new int[][][]{
          {{0, 1}, {2, 3}, {4, 5}},
          {{6, 7}, {8, 9}, {10, 11}},
          {{12, 13}, {14, 15}, {16, 17}, {18, 19}},
          {{20, 21}, {22, 23}, {24, 25}, {26, 27}}
      };
  
      @DataProvider
      private static Object[][] getArray3dRanges() {
          return new Object[][]{
              {"0:1,0:1,0:1", new int[][][]{
                  {{0, 1}, {2, 3}},
                  {{6, 7}, {8, 9}}}
              },
              {"1:2,1:2,0:1", new int[][][]{
                  {{8, 9}, {10, 11}},
                  {{14, 15}, {16, 17}}}
              },
              {"3,2,0", new int[][][]{
                  {{24}}}
              }
          };
      }
  
  }
  