/** * Copyright 2015-2017 The OpenZipkin Authors * * 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. */ package zipkin.internal; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.util.Arrays; import org.junit.Test; import sun.net.util.IPAddressUtil; import static org.assertj.core.api.Assertions.assertThat; import static zipkin.internal.Buffer.asciiSizeInBytes; import static zipkin.internal.Buffer.jsonEscapedSizeInBytes; import static zipkin.internal.Util.UTF_8; public class BufferTest { // Adapted from http://stackoverflow.com/questions/8511490/calculating-length-in-utf-8-of-java-string-without-actually-encoding-it @Test public void utf8SizeInBytes() { for (int codepoint = 0; codepoint <= 0x10FFFF; codepoint++) { if (codepoint == 0xD800) codepoint = 0xDFFF + 1; // skip surrogates if (Character.isDefined(codepoint)) { String test = new String(Character.toChars(codepoint)); int expected = test.getBytes(Util.UTF_8).length; int actual = Buffer.utf8SizeInBytes(test); if (actual != expected) { throw new AssertionError(actual + " length != " + expected + " for " + codepoint); } } } } /** Uses test data and codepoint wrapping trick from okhttp3.FormBodyTest */ @Test public void utf8_malformed() { for (int codepoint : Arrays.asList(0xD800, 0xDFFF, 0xD83D)) { String test = new String(new int[]{'a', codepoint, 'c'}, 0, 3); assertThat(Buffer.utf8SizeInBytes(test)) .isEqualTo(3); assertThat(new Buffer(3).writeUtf8(test).toByteArray()) .containsExactly('a', '?', 'c'); } } @Test public void emoji() { byte[] emojiBytes = {(byte) 0xF0, (byte) 0x9F, (byte) 0x98, (byte) 0x81}; String emoji = new String(emojiBytes, UTF_8); assertThat(Buffer.utf8SizeInBytes(emoji)) .isEqualTo(emojiBytes.length); assertThat(new Buffer(emojiBytes.length).writeUtf8(emoji).toByteArray()) .isEqualTo(emojiBytes); } // Test borrowed from guava InetAddressesTest @Test public void ipv6() { assertThat(writeIpV6("1:2:3:4:5:6:7:8")) .isEqualTo("1:2:3:4:5:6:7:8"); assertThat(writeIpV6("2001:0:0:4:0000:0:0:8")) .isEqualTo("2001:0:0:4::8"); assertThat(writeIpV6("2001:0:0:4:5:6:7:8")) .isEqualTo("2001::4:5:6:7:8"); assertThat(writeIpV6("2001:0:3:4:5:6:7:8")) .isEqualTo("2001::3:4:5:6:7:8"); assertThat(writeIpV6("0:0:3:0:0:0:0:ffff")) .isEqualTo("0:0:3::ffff"); assertThat(writeIpV6("0:0:0:4:0:0:0:ffff")) .isEqualTo("::4:0:0:0:ffff"); assertThat(writeIpV6("0:0:0:0:5:0:0:ffff")) .isEqualTo("::5:0:0:ffff"); assertThat(writeIpV6("1:0:0:4:0:0:7:8")) .isEqualTo("1::4:0:0:7:8"); assertThat(writeIpV6("0:0:0:0:0:0:0:0")) .isEqualTo("::"); assertThat(writeIpV6("0:0:0:0:0:0:0:1")) .isEqualTo("::1"); assertThat(writeIpV6("2001:0658:022a:cafe::")) .isEqualTo("2001:658:22a:cafe::"); assertThat(writeIpV6("::1.2.3.4")) .isEqualTo("::102:304"); } static String writeIpV6(String address) { byte[] ipv6 = IPAddressUtil.textToNumericFormatV6(address); byte[] buffered = new Buffer(Buffer.ipv6SizeInBytes(ipv6)).writeIpV6(ipv6).toByteArray(); return new String(buffered, UTF_8); } @Test public void asciiSizeInBytes_long() throws IOException { assertThat(asciiSizeInBytes(0L)).isEqualTo(1); assertThat(asciiSizeInBytes(-1005656679588439279L)).isEqualTo(20); assertThat(asciiSizeInBytes(-9223372036854775808L /* Long.MIN_VALUE */)).isEqualTo(20); assertThat(asciiSizeInBytes(123456789L)).isEqualTo(9); } @Test public void writeAscii_long() throws IOException { assertThat(writeAscii(-1005656679588439279L)) .isEqualTo("-1005656679588439279"); assertThat(writeAscii(0L)) .isEqualTo("0"); assertThat(writeAscii(-9223372036854775808L /* Long.MIN_VALUE */)) .isEqualTo("-9223372036854775808"); assertThat(writeAscii(123456789L)) .isEqualTo("123456789"); } static String writeAscii(long v) { byte[] buffered = new Buffer(Buffer.asciiSizeInBytes(v)).writeAscii(v).toByteArray(); return new String(buffered, UTF_8); } @Test public void jsonEscapedSizeInBytes_string() throws IOException { assertThat(jsonEscapedSizeInBytes(new String(new char[] {0, 'a', 1}))) .isEqualTo(13); assertThat(jsonEscapedSizeInBytes(new String(new char[] {'"', '\\', '\t', '\b'}))) .isEqualTo(8); assertThat(jsonEscapedSizeInBytes(new String(new char[] {'\n', '\r', '\f'}))) .isEqualTo(6); assertThat(jsonEscapedSizeInBytes("\u2028 and \u2029")) .isEqualTo(17); assertThat(jsonEscapedSizeInBytes("\"foo")) .isEqualTo(5); } @Test public void jsonEscapedSizeInBytes_bytes() throws IOException { assertThat(jsonEscapedSizeInBytes(new byte[] {0, 'a', 1})) .isEqualTo(13); assertThat(jsonEscapedSizeInBytes(new byte[] {'"', '\\', '\t', '\b'})) .isEqualTo(8); assertThat(jsonEscapedSizeInBytes(new byte[] {'\n', '\r', '\f'})) .isEqualTo(6); assertThat(jsonEscapedSizeInBytes("\u2028 and \u2029".getBytes(UTF_8))) .isEqualTo(17); assertThat(jsonEscapedSizeInBytes("\"foo".getBytes(UTF_8))) .isEqualTo(5); } @Test public void writeJsonEscaped_string() throws IOException { assertThat(writeJsonEscaped(new String(new char[] {0, 'a', 1}))) .isEqualTo("\\u0000a\\u0001"); assertThat(writeJsonEscaped(new String(new char[] {'"', '\\', '\t', '\b'}))) .isEqualTo("\\\"\\\\\\t\\b"); assertThat(writeJsonEscaped(new String(new char[] {'\n', '\r', '\f'}))) .isEqualTo("\\n\\r\\f"); assertThat(writeJsonEscaped("\u2028 and \u2029")) .isEqualTo("\\u2028 and \\u2029"); assertThat(writeJsonEscaped("\"foo")) .isEqualTo("\\\"foo"); } @Test public void writeJsonEscaped_bytes() throws IOException { assertThat(writeJsonEscaped(new byte[] {0, 'a', 1})) .isEqualTo("\\u0000a\\u0001"); assertThat(writeJsonEscaped(new byte[] {'"', '\\', '\t', '\b'})) .isEqualTo("\\\"\\\\\\t\\b"); assertThat(writeJsonEscaped(new byte[] {'\n', '\r', '\f'})) .isEqualTo("\\n\\r\\f"); assertThat(writeJsonEscaped("\u2028 and \u2029".getBytes(UTF_8))) .isEqualTo("\\u2028 and \\u2029"); assertThat(writeJsonEscaped("\"foo".getBytes(UTF_8))) .isEqualTo("\\\"foo"); } static String writeJsonEscaped(String v) { byte[] buffered = new Buffer(jsonEscapedSizeInBytes(v)).writeJsonEscaped(v).toByteArray(); return new String(buffered, UTF_8); } static String writeJsonEscaped(byte[] v) { byte[] buffered = new Buffer(jsonEscapedSizeInBytes(v)).writeJsonEscaped(v).toByteArray(); return new String(buffered, UTF_8); } // Test creating Buffer for a long string @Test public void writeString() throws UnsupportedEncodingException { StringBuffer stringBuffer = new StringBuffer(); for (int i = 0 ; i < 100000 ; i ++) { stringBuffer.append("a"); } String string = stringBuffer.toString(); byte[] buffered = new Buffer(Buffer.asciiSizeInBytes(string)).writeAscii(string).toByteArray(); assertThat(new String(buffered, "US-ASCII")).isEqualTo(string); } }