All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonTest.okio.CommonOptionsTest.kt Maven / Gradle / Ivy

There is a newer version: 4.0.0
Show newest version
/*
 * Copyright (C) 2018 Square, Inc.
 *
 * 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 okio

import okio.ByteString.Companion.encodeUtf8
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
import kotlin.test.fail

class CommonOptionsTest {
  /** Confirm that options prefers the first-listed option, not the longest or shortest one. */
  @Test fun optionOrderTakesPrecedence() {
    assertSelect("abcdefg", 0, "abc", "abcdef")
    assertSelect("abcdefg", 0, "abcdef", "abc")
  }

  @Test fun simpleOptionsTrie() {
    assertEquals(
      utf8Options("hotdog", "hoth", "hot").trieString(),
      """
        |hot
        |   -> 2
        |   d
        |    og -> 0
        |   h -> 1
        |""".trimMargin()
    )
  }

  @Test fun realisticOptionsTrie() {
    // These are the fields of OkHttpClient in 3.10.
    val options = utf8Options(
      "dispatcher",
      "proxy",
      "protocols",
      "connectionSpecs",
      "interceptors",
      "networkInterceptors",
      "eventListenerFactory",
      "proxySelector", // No index 7 in the trie because 'proxy' is a prefix!
      "cookieJar",
      "cache",
      "internalCache",
      "socketFactory",
      "sslSocketFactory",
      "certificateChainCleaner",
      "hostnameVerifier",
      "certificatePinner",
      "proxyAuthenticator", // No index 16 in the trie because 'proxy' is a prefix!
      "authenticator",
      "connectionPool",
      "dns",
      "followSslRedirects",
      "followRedirects",
      "retryOnConnectionFailure",
      "connectTimeout",
      "readTimeout",
      "writeTimeout",
      "pingInterval"
    )
    assertEquals(
      options.trieString(),
      """
        |a
        | uthenticator -> 17
        |c
        | a
        |  che -> 9
        | e
        |  rtificate
        |           C
        |            hainCleaner -> 13
        |           P
        |            inner -> 15
        | o
        |  n
        |   nect
        |       T
        |        imeout -> 23
        |       i
        |        on
        |          P
        |           ool -> 18
        |          S
        |           pecs -> 3
        |  o
        |   kieJar -> 8
        |d
        | i
        |  spatcher -> 0
        | n
        |  s -> 19
        |e
        | ventListenerFactory -> 6
        |f
        | ollow
        |      R
        |       edirects -> 21
        |      S
        |       slRedirects -> 20
        |h
        | ostnameVerifier -> 14
        |i
        | nter
        |     c
        |      eptors -> 4
        |     n
        |      alCache -> 10
        |n
        | etworkInterceptors -> 5
        |p
        | i
        |  ngInterval -> 26
        | r
        |  o
        |   t
        |    ocols -> 2
        |   x
        |    y -> 1
        |r
        | e
        |  a
        |   dTimeout -> 24
        |  t
        |   ryOnConnectionFailure -> 22
        |s
        | o
        |  cketFactory -> 11
        | s
        |  lSocketFactory -> 12
        |w
        | riteTimeout -> 25
        |""".trimMargin()
    )
    assertSelect("", -1, options)
    assertSelect("a", -1, options)
    assertSelect("eventListenerFactor", -1, options)
    assertSelect("dnst", 19, options)
    assertSelect("proxyproxy", 1, options)
    assertSelect("prox", -1, options)

    assertSelect("dispatcher", 0, options)
    assertSelect("proxy", 1, options)
    assertSelect("protocols", 2, options)
    assertSelect("connectionSpecs", 3, options)
    assertSelect("interceptors", 4, options)
    assertSelect("networkInterceptors", 5, options)
    assertSelect("eventListenerFactory", 6, options)
    assertSelect("proxySelector", 1, options) // 'proxy' is a prefix.
    assertSelect("cookieJar", 8, options)
    assertSelect("cache", 9, options)
    assertSelect("internalCache", 10, options)
    assertSelect("socketFactory", 11, options)
    assertSelect("sslSocketFactory", 12, options)
    assertSelect("certificateChainCleaner", 13, options)
    assertSelect("hostnameVerifier", 14, options)
    assertSelect("certificatePinner", 15, options)
    assertSelect("proxyAuthenticator", 1, options) // 'proxy' is a prefix.
    assertSelect("authenticator", 17, options)
    assertSelect("connectionPool", 18, options)
    assertSelect("dns", 19, options)
    assertSelect("followSslRedirects", 20, options)
    assertSelect("followRedirects", 21, options)
    assertSelect("retryOnConnectionFailure", 22, options)
    assertSelect("connectTimeout", 23, options)
    assertSelect("readTimeout", 24, options)
    assertSelect("writeTimeout", 25, options)
    assertSelect("pingInterval", 26, options)
  }

  @Test fun emptyOptions() {
    val options = utf8Options()
    assertSelect("", -1, options)
    assertSelect("a", -1, options)
    assertSelect("abc", -1, options)
  }

  @Test fun emptyStringInOptionsTrie() {
    assertFailsWith {
      utf8Options("")
    }
    assertFailsWith {
      utf8Options("abc", "")
    }
  }

  @Test fun multipleIdenticalValues() {
    try {
      utf8Options("abc", "abc")
      fail()
    } catch (expected: IllegalArgumentException) {
      assertEquals(expected.message, "duplicate option: [text=abc]")
    }
  }

  @Test fun prefixesAreStripped() {
    val options = utf8Options("abcA", "abc", "abcB")
    assertEquals(
      options.trieString(),
      """
        |abc
        |   -> 1
        |   A -> 0
        |""".trimMargin()
    )
    assertSelect("abc", 1, options)
    assertSelect("abcA", 0, options)
    assertSelect("abcB", 1, options)
    assertSelect("abcC", 1, options)
    assertSelect("ab", -1, options)
  }

  @Test fun multiplePrefixesAreStripped() {
    assertEquals(
      utf8Options("a", "ab", "abc", "abcd", "abcde").trieString(),
      """
        |a -> 0
        |""".trimMargin()
    )
    assertEquals(
      utf8Options("abc", "a", "ab", "abe", "abcd", "abcf").trieString(),
      """
        |a
        | -> 1
        | bc -> 0
        |""".trimMargin()
    )
    assertEquals(
      utf8Options("abc", "ab", "a").trieString(),
      """
        |a
        | -> 2
        | b
        |  -> 1
        |  c -> 0
        |""".trimMargin()
    )
    assertEquals(
      utf8Options("abcd", "abce", "abc", "abcf", "abcg").trieString(),
      """
        |abc
        |   -> 2
        |   d -> 0
        |   e -> 1
        |""".trimMargin()
    )
  }

  @Test fun scan() {
    val options = utf8Options("abc")
    assertSelect("abcde", 0, options)
  }

  @Test fun scanReturnsPrefix() {
    val options = utf8Options("abcdefg", "ab")
    assertSelect("ab", 1, options)
    assertSelect("abcd", 1, options)
    assertSelect("abcdefg", 0, options)
    assertSelect("abcdefghi", 0, options)
    assertSelect("abcdhi", 1, options)
  }

  @Test fun select() {
    val options = utf8Options("a", "b", "c")
    assertSelect("a", 0, options)
    assertSelect("b", 1, options)
    assertSelect("c", 2, options)
    assertSelect("d", -1, options)
    assertSelect("aa", 0, options)
    assertSelect("bb", 1, options)
    assertSelect("cc", 2, options)
    assertSelect("dd", -1, options)
  }

  @Test fun selectSelect() {
    val options = utf8Options("aa", "ab", "ba", "bb")
    assertSelect("a", -1, options)
    assertSelect("b", -1, options)
    assertSelect("c", -1, options)
    assertSelect("aa", 0, options)
    assertSelect("ab", 1, options)
    assertSelect("ac", -1, options)
    assertSelect("ba", 2, options)
    assertSelect("bb", 3, options)
    assertSelect("bc", -1, options)
    assertSelect("ca", -1, options)
    assertSelect("cb", -1, options)
    assertSelect("cc", -1, options)
  }

  @Test fun selectScan() {
    val options = utf8Options("abcd", "defg")
    assertSelect("a", -1, options)
    assertSelect("d", -1, options)
    assertSelect("h", -1, options)
    assertSelect("ab", -1, options)
    assertSelect("ae", -1, options)
    assertSelect("de", -1, options)
    assertSelect("db", -1, options)
    assertSelect("hi", -1, options)
    assertSelect("abcd", 0, options)
    assertSelect("aefg", -1, options)
    assertSelect("defg", 1, options)
    assertSelect("dbcd", -1, options)
    assertSelect("hijk", -1, options)
    assertSelect("abcdh", 0, options)
    assertSelect("defgh", 1, options)
    assertSelect("hijkl", -1, options)
  }

  @Test fun scanSelect() {
    val options = utf8Options("abcd", "abce")
    assertSelect("a", -1, options)
    assertSelect("f", -1, options)
    assertSelect("abc", -1, options)
    assertSelect("abf", -1, options)
    assertSelect("abcd", 0, options)
    assertSelect("abce", 1, options)
    assertSelect("abcf", -1, options)
    assertSelect("abcdf", 0, options)
    assertSelect("abcef", 1, options)
  }

  @Test fun scanSpansSegments() {
    val options = utf8Options("abcd")
    assertSelect(bufferWithSegments("a", "bcd"), 0, options)
    assertSelect(bufferWithSegments("a", "bcde"), 0, options)
    assertSelect(bufferWithSegments("ab", "cd"), 0, options)
    assertSelect(bufferWithSegments("ab", "cde"), 0, options)
    assertSelect(bufferWithSegments("abc", "d"), 0, options)
    assertSelect(bufferWithSegments("abc", "de"), 0, options)
    assertSelect(bufferWithSegments("abcd", "e"), 0, options)
    assertSelect(bufferWithSegments("a", "bce"), -1, options)
    assertSelect(bufferWithSegments("a", "bce"), -1, options)
    assertSelect(bufferWithSegments("ab", "ce"), -1, options)
    assertSelect(bufferWithSegments("ab", "ce"), -1, options)
    assertSelect(bufferWithSegments("abc", "e"), -1, options)
    assertSelect(bufferWithSegments("abc", "ef"), -1, options)
    assertSelect(bufferWithSegments("abce", "f"), -1, options)
  }

  @Test fun selectSpansSegments() {
    val options = utf8Options("aa", "ab", "ba", "bb")
    assertSelect(bufferWithSegments("a", "a"), 0, options)
    assertSelect(bufferWithSegments("a", "b"), 1, options)
    assertSelect(bufferWithSegments("a", "c"), -1, options)
    assertSelect(bufferWithSegments("b", "a"), 2, options)
    assertSelect(bufferWithSegments("b", "b"), 3, options)
    assertSelect(bufferWithSegments("b", "c"), -1, options)
    assertSelect(bufferWithSegments("c", "a"), -1, options)
    assertSelect(bufferWithSegments("c", "b"), -1, options)
    assertSelect(bufferWithSegments("c", "c"), -1, options)
    assertSelect(bufferWithSegments("a", "ad"), 0, options)
    assertSelect(bufferWithSegments("a", "bd"), 1, options)
    assertSelect(bufferWithSegments("a", "cd"), -1, options)
    assertSelect(bufferWithSegments("b", "ad"), 2, options)
    assertSelect(bufferWithSegments("b", "bd"), 3, options)
    assertSelect(bufferWithSegments("b", "cd"), -1, options)
    assertSelect(bufferWithSegments("c", "ad"), -1, options)
    assertSelect(bufferWithSegments("c", "bd"), -1, options)
    assertSelect(bufferWithSegments("c", "cd"), -1, options)
  }

  private fun utf8Options(vararg options: String): Options {
    return Options.of(*options.map { it.encodeUtf8() }.toTypedArray())
  }

  private fun assertSelect(data: String, expected: Int, options: Options) {
    assertSelect(Buffer().writeUtf8(data), expected, options)
  }

  private fun assertSelect(data: String, expected: Int, vararg options: String) {
    assertSelect(data, expected, utf8Options(*options))
  }

  private fun assertSelect(data: Buffer, expected: Int, options: Options) {
    val initialSize = data.size
    val actual = data.select(options)

    assertEquals(actual, expected)
    if (expected == -1) {
      assertEquals(data.size, initialSize)
    } else {
      assertEquals(data.size + options[expected].size, initialSize)
    }
  }

  private fun Options.trieString(): String {
    val result = StringBuilder()
    printTrieNode(result, 0)
    return result.toString()
  }

  private fun Options.printTrieNode(out: StringBuilder, offset: Int = 0, indent: String = "") {
    if (trie[offset + 1] != -1) {
      // Print the prefix.
      out.append("$indent-> ${trie[offset + 1]}\n")
    }

    if (trie[offset] > 0) {
      // Print the select.
      val selectChoiceCount = trie[offset]
      for (i in 0 until selectChoiceCount) {
        out.append("$indent${trie[offset + 2 + i].toChar()}")
        printTrieResult(out, trie[offset + 2 + selectChoiceCount + i], "$indent ")
      }
    } else {
      // Print the scan.
      val scanByteCount = -1 * trie[offset]
      out.append(indent)
      for (i in 0 until scanByteCount) {
        out.append(trie[offset + 2 + i].toChar())
      }
      printTrieResult(out, trie[offset + 2 + scanByteCount], "$indent${" ".repeat(scanByteCount)}")
    }
  }

  private fun Options.printTrieResult(out: StringBuilder, result: Int, indent: String) {
    if (result >= 0) {
      out.append(" -> $result\n")
    } else {
      out.append("\n")
      printTrieNode(out, -1 * result, indent)
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy