001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase.types;
019
020import static org.junit.jupiter.api.Assertions.assertArrayEquals;
021import static org.junit.jupiter.api.Assertions.assertEquals;
022import static org.junit.jupiter.api.Assertions.assertThrows;
023
024import org.apache.hadoop.hbase.testclassification.MiscTests;
025import org.apache.hadoop.hbase.testclassification.SmallTests;
026import org.apache.hadoop.hbase.util.Bytes;
027import org.apache.hadoop.hbase.util.Order;
028import org.apache.hadoop.hbase.util.PositionedByteRange;
029import org.apache.hadoop.hbase.util.SimplePositionedMutableByteRange;
030import org.junit.jupiter.api.Tag;
031import org.junit.jupiter.api.Test;
032
033@Tag(MiscTests.TAG)
034@Tag(SmallTests.TAG)
035public class TestTerminatedWrapper {
036
037  static final String[] VALUES_STRINGS = new String[] { "", "1", "22", "333", "4444", "55555",
038    "666666", "7777777", "88888888", "999999999", };
039
040  static final byte[][] VALUES_BYTES = new byte[VALUES_STRINGS.length][];
041  static {
042    for (int i = 0; i < VALUES_STRINGS.length; i++) {
043      VALUES_BYTES[i] = Bytes.toBytes(VALUES_STRINGS[i]);
044    }
045  }
046
047  static final byte[][] TERMINATORS = new byte[][] { new byte[] { -2 }, Bytes.toBytes("foo") };
048
049  @Test
050  public void testEmptyDelimiter() {
051    assertThrows(IllegalArgumentException.class,
052      () -> new TerminatedWrapper<>(new RawBytes(Order.ASCENDING), ""));
053  }
054
055  @Test
056  public void testNullDelimiter() {
057    assertThrows(IllegalArgumentException.class, () -> new RawBytesTerminated((byte[]) null));
058    // new TerminatedWrapper<byte[]>(new RawBytes(), (byte[]) null);
059  }
060
061  @Test
062  public void testEncodedValueContainsTerm() {
063    final DataType<byte[]> type = new TerminatedWrapper<>(new RawBytes(Order.ASCENDING), "foo");
064    final PositionedByteRange buff = new SimplePositionedMutableByteRange(16);
065    assertThrows(IllegalArgumentException.class, () -> {
066      type.encode(buff, Bytes.toBytes("hello foobar!"));
067    });
068  }
069
070  @Test
071  public void testReadWriteSkippable() {
072    final PositionedByteRange buff = new SimplePositionedMutableByteRange(14);
073    for (final OrderedString t : new OrderedString[] { new OrderedString(Order.ASCENDING),
074      new OrderedString(Order.DESCENDING) }) {
075      for (final byte[] term : TERMINATORS) {
076        for (final String val : VALUES_STRINGS) {
077          buff.setPosition(0);
078          final DataType<String> type = new TerminatedWrapper<>(t, term);
079          assertEquals(val.length() + 2 + term.length, type.encode(buff, val));
080          buff.setPosition(0);
081          assertEquals(val, type.decode(buff));
082          assertEquals(val.length() + 2 + term.length, buff.getPosition());
083        }
084      }
085    }
086  }
087
088  @Test
089  public void testReadWriteNonSkippable() {
090    PositionedByteRange buff = new SimplePositionedMutableByteRange(12);
091    for (Order ord : new Order[] { Order.ASCENDING, Order.DESCENDING }) {
092      for (byte[] term : TERMINATORS) {
093        for (byte[] val : VALUES_BYTES) {
094          buff.setPosition(0);
095          DataType<byte[]> type = new TerminatedWrapper<>(new RawBytes(ord), term);
096          assertEquals(val.length + term.length, type.encode(buff, val));
097          buff.setPosition(0);
098          assertArrayEquals(val, type.decode(buff));
099          assertEquals(val.length + term.length, buff.getPosition());
100        }
101      }
102    }
103  }
104
105  @Test
106  public void testSkipSkippable() {
107    final PositionedByteRange buff = new SimplePositionedMutableByteRange(14);
108    for (final OrderedString t : new OrderedString[] { new OrderedString(Order.ASCENDING),
109      new OrderedString(Order.DESCENDING) }) {
110      for (final byte[] term : TERMINATORS) {
111        for (final String val : VALUES_STRINGS) {
112          buff.setPosition(0);
113          final DataType<String> type = new TerminatedWrapper<>(t, term);
114          final int expected = val.length() + 2 + term.length;
115          assertEquals(expected, type.encode(buff, val));
116          buff.setPosition(0);
117          assertEquals(expected, type.skip(buff));
118          assertEquals(expected, buff.getPosition());
119        }
120      }
121    }
122  }
123
124  @Test
125  public void testSkipNonSkippable() {
126    PositionedByteRange buff = new SimplePositionedMutableByteRange(12);
127    for (Order ord : new Order[] { Order.ASCENDING, Order.DESCENDING }) {
128      for (byte[] term : TERMINATORS) {
129        for (byte[] val : VALUES_BYTES) {
130          buff.setPosition(0);
131          DataType<byte[]> type = new TerminatedWrapper<>(new RawBytes(ord), term);
132          int expected = type.encode(buff, val);
133          buff.setPosition(0);
134          assertEquals(expected, type.skip(buff));
135          assertEquals(expected, buff.getPosition());
136        }
137      }
138    }
139  }
140
141  @Test
142  public void testInvalidSkip() {
143    final PositionedByteRange buff = new SimplePositionedMutableByteRange(Bytes.toBytes("foo"));
144    final DataType<byte[]> type =
145      new TerminatedWrapper<>(new RawBytes(Order.ASCENDING), new byte[] { 0x00 });
146    assertThrows(IllegalArgumentException.class, () -> {
147      type.skip(buff);
148    });
149  }
150}