package org.rapidoid.buffer; /* * #%L * rapidoid-buffer * %% * Copyright (C) 2014 - 2017 Nikolche Mihajlovski and contributors * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * #L% */ import org.junit.Test; import org.rapidoid.annotation.Authors; import org.rapidoid.annotation.Since; import org.rapidoid.bytes.BytesUtil; import org.rapidoid.commons.Rnd; import org.rapidoid.commons.Str; import org.rapidoid.data.BufRange; import org.rapidoid.data.BufRanges; import org.rapidoid.u.U; import static org.rapidoid.util.Constants.*; @Authors("Nikolche Mihajlovski") @Since("2.0.0") public class BufTest extends BufferTestCommons { @Test public void shouldAppendData() { BufGroup bufs = new BufGroup(4); Buf buf = bufs.newBuf(); eq(buf, ""); buf.append(""); eq(buf, ""); buf.append("Foo"); eq(buf, "Foo"); buf.append("Bar"); eq(buf, "FooBar"); buf.append("Bazinga"); eq(buf, "FooBarBazinga"); buf.append(""); eq(buf, "FooBarBazinga"); buf.append("X"); eq(buf, "FooBarBazingaX"); buf.append("Y"); eq(buf, "FooBarBazingaXY"); buf.append("Z"); eq(buf, "FooBarBazingaXYZ"); buf.append("W"); eq(buf, "FooBarBazingaXYZW"); } @Test public void shouldShrinkOnLeft() { BufGroup bufs = new BufGroup(4); Buf buf = bufs.newBuf(); buf.append("abcdefgh-foo-bar-123456789-the-end"); eq(buf, "abcdefgh-foo-bar-123456789-the-end"); buf.deleteBefore(1); eq(buf, "bcdefgh-foo-bar-123456789-the-end"); buf.deleteBefore(2); eq(buf, "defgh-foo-bar-123456789-the-end"); buf.deleteBefore(1); eq(buf, "efgh-foo-bar-123456789-the-end"); buf.deleteBefore(1); eq(buf, "fgh-foo-bar-123456789-the-end"); buf.deleteBefore(4); eq(buf, "foo-bar-123456789-the-end"); buf.deleteBefore(10); eq(buf, "3456789-the-end"); buf.deleteBefore(8); eq(buf, "the-end"); buf.deleteBefore(4); eq(buf, "end"); buf.deleteBefore(2); eq(buf, "d"); buf.deleteBefore(1); eq(buf, ""); buf.deleteBefore(0); eq(buf, ""); } @Test public void shouldShrinkOnRight() { BufGroup bufs = new BufGroup(4); Buf buf = bufs.newBuf(); buf.append("abcdefgh-foo-bar-123456789-the-end"); eq(buf, "abcdefgh-foo-bar-123456789-the-end"); buf.deleteLast(1); eq(buf, "abcdefgh-foo-bar-123456789-the-en"); buf.deleteLast(2); eq(buf, "abcdefgh-foo-bar-123456789-the-"); buf.deleteLast(1); eq(buf, "abcdefgh-foo-bar-123456789-the"); buf.deleteLast(1); eq(buf, "abcdefgh-foo-bar-123456789-th"); buf.deleteLast(4); eq(buf, "abcdefgh-foo-bar-12345678"); buf.deleteLast(10); eq(buf, "abcdefgh-foo-ba"); buf.deleteLast(8); eq(buf, "abcdefg"); buf.deleteLast(4); eq(buf, "abc"); buf.deleteLast(2); eq(buf, "a"); buf.deleteLast(1); eq(buf, ""); buf.deleteLast(0); eq(buf, ""); } @Test public void shouldParseNumbers() { BufGroup bufs = new BufGroup(4); Buf buf = bufs.newBuf(); buf.append("5a1234567890fg-3450fg0x45g-3"); buf.setReadOnly(true); eq(buf.getN(new BufRange(0, 1)), 5); eq(buf.getN(new BufRange(2, 10)), 1234567890); eq(buf.getN(new BufRange(14, 5)), -3450); eq(buf.getN(new BufRange(21, 1)), 0); eq(buf.getN(new BufRange(23, 2)), 45); eq(buf.getN(new BufRange(26, 2)), -3); } @Test public void shouldFindSubsequences() { BufGroup bufs = new BufGroup(4); Buf buf = bufs.newBuf(); /************* 0123456789012345678901234567890 */ // buf.append("-abc-xAaw-54-bAr--The-End-"); buf.append("-abc-xaaw-54-bar--the-end-"); buf.setReadOnly(true); int max = buf.size(); checkMatch(buf, 0, max, "a", 1, 6, 7, 14, -1); checkMatch(buf, 2, max, "a", 6, 7, 14, -1); checkMatch(buf, 5, max, "a", 6, 7, 14, -1); checkMatch(buf, 7, max, "a", 7, 14, -1); checkMatch(buf, 0, max, "abc", 1, -1); checkMatch(buf, 0, max, "-abc", 0, -1); checkMatch(buf, 0, max, "the", 18, -1); checkMatch(buf, 0, max, "end", 22, -1); checkMatch(buf, 0, max, "+", -1); checkMatch(buf, 0, max, "-", 0, 4, 9, 12, 16, 17, 21, 25, -1); } @Test public void testScanUntil() { BufGroup bufs = new BufGroup(4); Buf buf = bufs.newBuf(); buf.append("first second third\r\na b c\r\n"); buf.setReadOnly(true); buf.position(0); buf.limit(buf.size()); BufRange range = new BufRange(); buf.scanUntil(SPACE, range); eq(buf.get(range), "first"); buf.scanUntil(SPACE, range); eq(buf.get(range), "second"); buf.scanUntil(SPACE, range); eq(buf.get(range), ""); buf.scanLn(range); eq(buf.get(range), "third"); buf.scanUntil(SPACE, range); eq(buf.get(range), "a"); buf.scanUntil(SPACE, range); eq(buf.get(range), "b"); buf.scanLn(range); eq(buf.get(range), "c"); isFalse(buf.hasRemaining()); } @Test public void testScanWhile() { BufGroup bufs = new BufGroup(4); Buf buf = bufs.newBuf(); buf.append("abc: xy:"); buf.setReadOnly(true); buf.position(0); buf.limit(buf.size()); BufRange range = new BufRange(); buf.scanUntil(COL, range); eq(buf.get(range), "abc"); eq(buf.position(), 4); buf.scanWhile(SPACE, range); eq(range, 4, 2); eq(buf.position(), 6); buf.scanUntil(COL, range); eq(buf.get(range), "xy"); eq(buf.position(), 9); } @Test public void testScanUntilAndMatchPrefix() { final int NO_PREFIX = 0; BufRange range = new BufRange(); eq(BytesUtil.scanUntilAndMatchPrefix(BytesUtil.from("\n"), range, LF, 0, 0, NO_PREFIX), 1); eq(range, 0, 0); eq(BytesUtil.scanUntilAndMatchPrefix(BytesUtil.from("a\n"), range, COL, 0, 0, NO_PREFIX), NOT_FOUND); eq(range, -1, 0); eq(BytesUtil.scanUntilAndMatchPrefix(BytesUtil.from("a\n"), range, LF, 0, 1, NO_PREFIX), 2); eq(range, 0, 1); eq(BytesUtil.scanUntilAndMatchPrefix(BytesUtil.from("ab:c"), range, COL, 0, 3, NO_PREFIX), 3); eq(range, 0, 2); for (int i = 0; i < 10; i++) { String s = Str.mul("a", i); eq(BytesUtil.scanUntilAndMatchPrefix(BytesUtil.from(s + ":"), range, COL, 0, i, NO_PREFIX), i + 1); eq(range, 0, i); eq(BytesUtil.scanLnAndMatchPrefix(BytesUtil.from(s + "\n"), range, 0, i, NO_PREFIX), i + 1); eq(range, 0, i); eq(BytesUtil.scanLnAndMatchPrefix(BytesUtil.from(s + "\r\n"), range, 0, i + 1, NO_PREFIX), i + 2); eq(range, 0, i); } eq(BytesUtil.scanLnAndMatchPrefix(BytesUtil.from("x\n"), range, 0, 0, NO_PREFIX), NOT_FOUND); eq(range, -1, 0); eq(BytesUtil.scanLnAndMatchPrefix(BytesUtil.from("x\r\n"), range, 0, 1, NO_PREFIX), NOT_FOUND); eq(range, -1, 0); eq(BytesUtil.scanLnAndMatchPrefix(BytesUtil.from("x\n"), range, 1, 1, NO_PREFIX), 2); eq(range, 1, 0); eq(BytesUtil.scanLnAndMatchPrefix(BytesUtil.from("x\r\n"), range, 1, 2, NO_PREFIX), 3); eq(range, 1, 0); } @Test public void testScanLnLn() { for (int factor = 1; factor <= 10; factor++) { BufGroup bufs = new BufGroup((int) Math.pow(2, factor)); Buf buf = bufs.newBuf(); String s = "GET /hi H\naa: bb\nxyz\r\n\r\n"; buf.append(s); buf.setReadOnly(true); buf.position(0); buf.limit(buf.size()); BufRange verb = new BufRange(); BufRange uri = new BufRange(); BufRange protocol = new BufRange(); buf.scanUntil(SPACE, verb); eq(s, verb, "GET"); buf.scanUntil(SPACE, uri); eq(s, uri, "/hi"); buf.scanLn(protocol); eq(s, protocol, "H"); BufRanges headers = new BufRanges(10); buf.scanLnLn(headers.reset()); eq(headers.count, 2); eq(s, headers.ranges[0], "aa: bb"); eq(s, headers.ranges[1], "xyz"); } } @Test public void testPutNumAsText() { BufGroup bufs = new BufGroup(2); String num = "1234567890"; for (int dig = 1; dig <= 10; dig++) { int n = U.num(num.substring(0, dig)); Buf buf = bufs.newBuf(); buf.append(Str.mul(" ", dig + 2)); buf.putNumAsText(1, n, true); eq(buf.asText(), " " + n + " "); Buf buf2 = bufs.newBuf(); buf2.append(Str.mul(" ", dig + 3)); buf2.putNumAsText(1, -n, true); eq(buf2.asText(), " " + (-n) + " "); Buf buf3 = bufs.newBuf(); buf3.append(Str.mul(" ", dig + 2)); buf3.putNumAsText(dig, n, false); eq(buf3.asText(), " " + n + " "); Buf buf4 = bufs.newBuf(); buf4.append(Str.mul(" ", dig + 3)); buf4.putNumAsText(dig + 1, -n, false); eq(buf4.asText(), " " + (-n) + " "); Buf buf5 = bufs.newBuf(); buf5.append(" "); buf5.putNumAsText(1, n, true); eq(buf5.asText(), " " + n); Buf buf6 = bufs.newBuf(); buf6.append(Str.mul(" ", 20)); buf6.putNumAsText(15, n, false); eq(buf6.asText(), Str.mul(" ", 16 - dig) + n + Str.mul(" ", 4)); Buf buf7 = bufs.newBuf(); buf7.append(Str.mul(" ", 20)); buf7.putNumAsText(5, n, true); eq(buf7.asText(), Str.mul(" ", 5) + n + Str.mul(" ", 15 - dig)); } } @Test public void testDeleteAfter() { BufGroup bufs = new BufGroup(16); Buf buf = bufs.newBuf(); int size = 0; for (int i = 0; i < 1000000; i++) { int add = Rnd.rnd(100); for (int j = 0; j < 5; j++) { size += add; buf.append(Str.mul(" ", add)); eq(buf.size(), size); } for (int j = 0; j < 5; j++) { if (buf.size() > 0) { if (Rnd.rnd(2) == 0) { int delFrom = Rnd.rnd(size); int delN = size - delFrom; size -= delN; buf.deleteAfter(delFrom); } else { int delN = Rnd.rnd(size); size -= delN; buf.deleteBefore(delN); } } } } } private void checkMatch(Buf buf, int start, int limit, String match, int... positions) { for (int pos : positions) { int p = BytesUtil.find(buf.bytes(), start, limit, match.getBytes(), true); eq(p, pos); start = p + 1; } } }