< prev index next >

test/jdk/java/net/httpclient/http2/jdk.incubator.httpclient/jdk/incubator/http/internal/hpack/HeaderTableTest.java

Print this page


   1 /*
   2  * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */


  99        "          | 49    | proxy-authorization         |               |\n" +
 100        "          | 50    | range                       |               |\n" +
 101        "          | 51    | referer                     |               |\n" +
 102        "          | 52    | refresh                     |               |\n" +
 103        "          | 53    | retry-after                 |               |\n" +
 104        "          | 54    | server                      |               |\n" +
 105        "          | 55    | set-cookie                  |               |\n" +
 106        "          | 56    | strict-transport-security   |               |\n" +
 107        "          | 57    | transfer-encoding           |               |\n" +
 108        "          | 58    | user-agent                  |               |\n" +
 109        "          | 59    | vary                        |               |\n" +
 110        "          | 60    | via                         |               |\n" +
 111        "          | 61    | www-authenticate            |               |\n";
 112     // @formatter:on
 113 
 114     private static final int STATIC_TABLE_LENGTH = createStaticEntries().size();
 115     private final Random rnd = newRandom();
 116 
 117     @Test
 118     public void staticData() {
 119         HeaderTable table = new HeaderTable(0);
 120         Map<Integer, HeaderField> staticHeaderFields = createStaticEntries();
 121 
 122         Map<String, Integer> minimalIndexes = new HashMap<>();
 123 
 124         for (Map.Entry<Integer, HeaderField> e : staticHeaderFields.entrySet()) {
 125             Integer idx = e.getKey();
 126             String hName = e.getValue().name;
 127             Integer midx = minimalIndexes.get(hName);
 128             if (midx == null) {
 129                 minimalIndexes.put(hName, idx);
 130             } else {
 131                 minimalIndexes.put(hName, Math.min(idx, midx));
 132             }
 133         }
 134 
 135         staticHeaderFields.entrySet().forEach(
 136                 e -> {
 137                     // lookup
 138                     HeaderField actualHeaderField = table.get(e.getKey());
 139                     HeaderField expectedHeaderField = e.getValue();


 142                     // reverse lookup (name, value)
 143                     String hName = expectedHeaderField.name;
 144                     String hValue = expectedHeaderField.value;
 145                     int expectedIndex = e.getKey();
 146                     int actualIndex = table.indexOf(hName, hValue);
 147 
 148                     assertEquals(actualIndex, expectedIndex);
 149 
 150                     // reverse lookup (name)
 151                     int expectedMinimalIndex = minimalIndexes.get(hName);
 152                     int actualMinimalIndex = table.indexOf(hName, "blah-blah");
 153 
 154                     assertEquals(-actualMinimalIndex, expectedMinimalIndex);
 155                 }
 156         );
 157     }
 158 
 159     @Test
 160     public void constructorSetsMaxSize() {
 161         int size = rnd.nextInt(64);
 162         HeaderTable t = new HeaderTable(size);
 163         assertEquals(t.size(), 0);
 164         assertEquals(t.maxSize(), size);
 165     }
 166 
 167     @Test
 168     public void negativeMaximumSize() {
 169         int maxSize = -(rnd.nextInt(100) + 1); // [-100, -1]
 170         IllegalArgumentException e =
 171                 assertVoidThrows(IllegalArgumentException.class,
 172                         () -> new HeaderTable(0).setMaxSize(maxSize));
 173         assertExceptionMessageContains(e, "maxSize");
 174     }
 175 
 176     @Test
 177     public void zeroMaximumSize() {
 178         HeaderTable table = new HeaderTable(0);
 179         table.setMaxSize(0);
 180         assertEquals(table.maxSize(), 0);
 181     }
 182 
 183     @Test
 184     public void negativeIndex() {
 185         int idx = -(rnd.nextInt(256) + 1); // [-256, -1]
 186         IllegalArgumentException e =
 187                 assertVoidThrows(IllegalArgumentException.class,
 188                         () -> new HeaderTable(0).get(idx));
 189         assertExceptionMessageContains(e, "index");
 190     }
 191 
 192     @Test
 193     public void zeroIndex() {
 194         IllegalArgumentException e =
 195                 assertThrows(IllegalArgumentException.class,
 196                         () -> new HeaderTable(0).get(0));
 197         assertExceptionMessageContains(e, "index");
 198     }
 199 
 200     @Test
 201     public void length() {
 202         HeaderTable table = new HeaderTable(0);
 203         assertEquals(table.length(), STATIC_TABLE_LENGTH);
 204     }
 205 
 206     @Test
 207     public void indexOutsideStaticRange() {
 208         HeaderTable table = new HeaderTable(0);
 209         int idx = table.length() + (rnd.nextInt(256) + 1);
 210         IllegalArgumentException e =
 211                 assertThrows(IllegalArgumentException.class,
 212                         () -> table.get(idx));
 213         assertExceptionMessageContains(e, "index");
 214     }
 215 
 216     @Test
 217     public void entryPutAfterStaticArea() {
 218         HeaderTable table = new HeaderTable(256);
 219         int idx = table.length() + 1;
 220         assertThrows(IllegalArgumentException.class, () -> table.get(idx));
 221 
 222         byte[] bytes = new byte[32];
 223         rnd.nextBytes(bytes);
 224         String name = new String(bytes, StandardCharsets.ISO_8859_1);
 225         String value = "custom-value";
 226 
 227         table.put(name, value);
 228         HeaderField f = table.get(idx);
 229         assertEquals(name, f.name);
 230         assertEquals(value, f.value);
 231     }
 232 
 233     @Test
 234     public void staticTableHasZeroSize() {
 235         HeaderTable table = new HeaderTable(0);
 236         assertEquals(0, table.size());
 237     }
 238 
 239     @Test
 240     public void lowerIndexPriority() {
 241         HeaderTable table = new HeaderTable(256);
 242         int oldLength = table.length();
 243         table.put("bender", "rodriguez");
 244         table.put("bender", "rodriguez");
 245         table.put("bender", "rodriguez");
 246 
 247         assertEquals(table.length(), oldLength + 3); // more like an assumption
 248         int i = table.indexOf("bender", "rodriguez");
 249         assertEquals(oldLength + 1, i);
 250     }
 251 
 252     @Test
 253     public void lowerIndexPriority2() {
 254         HeaderTable table = new HeaderTable(256);
 255         int oldLength = table.length();
 256         int idx = rnd.nextInt(oldLength) + 1;
 257         HeaderField f = table.get(idx);
 258         table.put(f.name, f.value);
 259         assertEquals(table.length(), oldLength + 1);
 260         int i = table.indexOf(f.name, f.value);
 261         assertEquals(idx, i);
 262     }
 263 
 264     // TODO: negative indexes check
 265     // TODO: ensure full table clearance when adding huge header field
 266     // TODO: ensure eviction deletes minimum needed entries, not more
 267 
 268     @Test
 269     public void fifo() {
 270         HeaderTable t = new HeaderTable(Integer.MAX_VALUE);
 271         // Let's add a series of header fields
 272         int NUM_HEADERS = 32;



 273         for (int i = 1; i <= NUM_HEADERS; i++) {
 274             String s = String.valueOf(i);
 275             t.put(s, s);
 276         }
 277         // They MUST appear in a FIFO order:
 278         //   newer entries are at lower indexes
 279         //   older entries are at higher indexes
 280         for (int j = 1; j <= NUM_HEADERS; j++) {
 281             HeaderField f = t.get(STATIC_TABLE_LENGTH + j);
 282             int actualName = Integer.parseInt(f.name);
 283             int expectedName = NUM_HEADERS - j + 1;
 284             assertEquals(expectedName, actualName);
 285         }
 286         // Entries MUST be evicted in the order they were added:
 287         //   the newer the entry the later it is evicted
 288         for (int k = 1; k <= NUM_HEADERS; k++) {
 289             HeaderField f = t.evictEntry();
 290             assertEquals(String.valueOf(k), f.name);
 291         }
 292     }
 293 
 294     @Test
 295     public void indexOf() {
 296         HeaderTable t = new HeaderTable(Integer.MAX_VALUE);
 297         // Let's put a series of header fields
 298         int NUM_HEADERS = 32;



 299         for (int i = 1; i <= NUM_HEADERS; i++) {
 300             String s = String.valueOf(i);
 301             t.put(s, s);
 302         }
 303         // and verify indexOf (reverse lookup) returns correct indexes for
 304         // full lookup
 305         for (int j = 1; j <= NUM_HEADERS; j++) {
 306             String s = String.valueOf(j);
 307             int actualIndex = t.indexOf(s, s);
 308             int expectedIndex = STATIC_TABLE_LENGTH + NUM_HEADERS - j + 1;
 309             assertEquals(expectedIndex, actualIndex);
 310         }
 311         // as well as for just a name lookup
 312         for (int j = 1; j <= NUM_HEADERS; j++) {
 313             String s = String.valueOf(j);
 314             int actualIndex = t.indexOf(s, "blah");
 315             int expectedIndex = -(STATIC_TABLE_LENGTH + NUM_HEADERS - j + 1);
 316             assertEquals(expectedIndex, actualIndex);
 317         }
 318         // lookup for non-existent name returns 0
 319         assertEquals(0, t.indexOf("chupacabra", "1"));
 320     }
 321 
 322     @Test
 323     public void testToString() {
 324         testToString0();
 325     }
 326 
 327     @Test
 328     public void testToStringDifferentLocale() {

 329         Locale.setDefault(Locale.FRENCH);

 330         String s = format("%.1f", 3.1);
 331         assertEquals("3,1", s); // assumption of the test, otherwise the test is useless
 332         testToString0();



 333     }
 334 
 335     private void testToString0() {
 336         HeaderTable table = new HeaderTable(0);
 337         {
 338             table.setMaxSize(2048);
 339             String expected =
 340                     format("entries: %d; used %s/%s (%.1f%%)", 0, 0, 2048, 0.0);


 341             assertEquals(expected, table.toString());
 342         }
 343 
 344         {
 345             String name = "custom-name";
 346             String value = "custom-value";
 347             int size = 512;
 348 
 349             table.setMaxSize(size);
 350             table.put(name, value);
 351             String s = table.toString();
 352 
 353             int used = name.length() + value.length() + 32;
 354             double ratio = used * 100.0 / size;
 355 
 356             String expected =
 357                     format("entries: 1; used %s/%s (%.1f%%)", used, size, ratio);

 358             assertEquals(expected, s);
 359         }
 360 
 361         {
 362             table.setMaxSize(78);
 363             table.put(":method", "");
 364             table.put(":status", "");
 365             String s = table.toString();
 366             String expected =
 367                     format("entries: %d; used %s/%s (%.1f%%)", 2, 78, 78, 100.0);

 368             assertEquals(expected, s);
 369         }
 370     }
 371 
 372     @Test
 373     public void stateString() {
 374         HeaderTable table = new HeaderTable(256);
 375         table.put("custom-key", "custom-header");
 376         // @formatter:off
 377         assertEquals("[  1] (s =  55) custom-key: custom-header\n" +
 378                      "      Table size:  55", table.getStateString());
 379         // @formatter:on
 380     }
 381 
 382     private static Map<Integer, HeaderField> createStaticEntries() {
 383         Pattern line = Pattern.compile(
 384                 "\\|\\s*(?<index>\\d+?)\\s*\\|\\s*(?<name>.+?)\\s*\\|\\s*(?<value>.*?)\\s*\\|");
 385         Matcher m = line.matcher(SPEC);
 386         Map<Integer, HeaderField> result = new HashMap<>();
 387         while (m.find()) {
 388             int index = Integer.parseInt(m.group("index"));
 389             String name = m.group("name");
 390             String value = m.group("value");
 391             HeaderField f = new HeaderField(name, value);
 392             result.put(index, f);
 393         }
 394         return Collections.unmodifiableMap(result); // lol
   1 /*
   2  * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */


  99        "          | 49    | proxy-authorization         |               |\n" +
 100        "          | 50    | range                       |               |\n" +
 101        "          | 51    | referer                     |               |\n" +
 102        "          | 52    | refresh                     |               |\n" +
 103        "          | 53    | retry-after                 |               |\n" +
 104        "          | 54    | server                      |               |\n" +
 105        "          | 55    | set-cookie                  |               |\n" +
 106        "          | 56    | strict-transport-security   |               |\n" +
 107        "          | 57    | transfer-encoding           |               |\n" +
 108        "          | 58    | user-agent                  |               |\n" +
 109        "          | 59    | vary                        |               |\n" +
 110        "          | 60    | via                         |               |\n" +
 111        "          | 61    | www-authenticate            |               |\n";
 112     // @formatter:on
 113 
 114     private static final int STATIC_TABLE_LENGTH = createStaticEntries().size();
 115     private final Random rnd = newRandom();
 116 
 117     @Test
 118     public void staticData() {
 119         HeaderTable table = new HeaderTable(0, HPACK.getLogger());
 120         Map<Integer, HeaderField> staticHeaderFields = createStaticEntries();
 121 
 122         Map<String, Integer> minimalIndexes = new HashMap<>();
 123 
 124         for (Map.Entry<Integer, HeaderField> e : staticHeaderFields.entrySet()) {
 125             Integer idx = e.getKey();
 126             String hName = e.getValue().name;
 127             Integer midx = minimalIndexes.get(hName);
 128             if (midx == null) {
 129                 minimalIndexes.put(hName, idx);
 130             } else {
 131                 minimalIndexes.put(hName, Math.min(idx, midx));
 132             }
 133         }
 134 
 135         staticHeaderFields.entrySet().forEach(
 136                 e -> {
 137                     // lookup
 138                     HeaderField actualHeaderField = table.get(e.getKey());
 139                     HeaderField expectedHeaderField = e.getValue();


 142                     // reverse lookup (name, value)
 143                     String hName = expectedHeaderField.name;
 144                     String hValue = expectedHeaderField.value;
 145                     int expectedIndex = e.getKey();
 146                     int actualIndex = table.indexOf(hName, hValue);
 147 
 148                     assertEquals(actualIndex, expectedIndex);
 149 
 150                     // reverse lookup (name)
 151                     int expectedMinimalIndex = minimalIndexes.get(hName);
 152                     int actualMinimalIndex = table.indexOf(hName, "blah-blah");
 153 
 154                     assertEquals(-actualMinimalIndex, expectedMinimalIndex);
 155                 }
 156         );
 157     }
 158 
 159     @Test
 160     public void constructorSetsMaxSize() {
 161         int size = rnd.nextInt(64);
 162         HeaderTable t = new HeaderTable(size, HPACK.getLogger());
 163         assertEquals(t.size(), 0);
 164         assertEquals(t.maxSize(), size);
 165     }
 166 
 167     @Test
 168     public void negativeMaximumSize() {
 169         int maxSize = -(rnd.nextInt(100) + 1); // [-100, -1]
 170         IllegalArgumentException e =
 171                 assertVoidThrows(IllegalArgumentException.class,
 172                         () -> new HeaderTable(0, HPACK.getLogger()).setMaxSize(maxSize));
 173         assertExceptionMessageContains(e, "maxSize");
 174     }
 175 
 176     @Test
 177     public void zeroMaximumSize() {
 178         HeaderTable table = new HeaderTable(0, HPACK.getLogger());
 179         table.setMaxSize(0);
 180         assertEquals(table.maxSize(), 0);
 181     }
 182 
 183     @Test
 184     public void negativeIndex() {
 185         int idx = -(rnd.nextInt(256) + 1); // [-256, -1]
 186         IndexOutOfBoundsException e =
 187                 assertVoidThrows(IndexOutOfBoundsException.class,
 188                         () -> new HeaderTable(0, HPACK.getLogger()).get(idx));
 189         assertExceptionMessageContains(e, "index");
 190     }
 191 
 192     @Test
 193     public void zeroIndex() {
 194         IndexOutOfBoundsException e =
 195                 assertThrows(IndexOutOfBoundsException.class,
 196                         () -> new HeaderTable(0, HPACK.getLogger()).get(0));
 197         assertExceptionMessageContains(e, "index");
 198     }
 199 
 200     @Test
 201     public void length() {
 202         HeaderTable table = new HeaderTable(0, HPACK.getLogger());
 203         assertEquals(table.length(), STATIC_TABLE_LENGTH);
 204     }
 205 
 206     @Test
 207     public void indexOutsideStaticRange() {
 208         HeaderTable table = new HeaderTable(0, HPACK.getLogger());
 209         int idx = table.length() + (rnd.nextInt(256) + 1);
 210         IndexOutOfBoundsException e =
 211                 assertThrows(IndexOutOfBoundsException.class,
 212                         () -> table.get(idx));
 213         assertExceptionMessageContains(e, "index");
 214     }
 215 
 216     @Test
 217     public void entryPutAfterStaticArea() {
 218         HeaderTable table = new HeaderTable(256, HPACK.getLogger());
 219         int idx = table.length() + 1;
 220         assertThrows(IndexOutOfBoundsException.class, () -> table.get(idx));
 221 
 222         byte[] bytes = new byte[32];
 223         rnd.nextBytes(bytes);
 224         String name = new String(bytes, StandardCharsets.ISO_8859_1);
 225         String value = "custom-value";
 226 
 227         table.put(name, value);
 228         HeaderField f = table.get(idx);
 229         assertEquals(name, f.name);
 230         assertEquals(value, f.value);
 231     }
 232 
 233     @Test
 234     public void staticTableHasZeroSize() {
 235         HeaderTable table = new HeaderTable(0, HPACK.getLogger());
 236         assertEquals(0, table.size());
 237     }
 238 
 239     @Test
 240     public void lowerIndexPriority() {
 241         HeaderTable table = new HeaderTable(256, HPACK.getLogger());
 242         int oldLength = table.length();
 243         table.put("bender", "rodriguez");
 244         table.put("bender", "rodriguez");
 245         table.put("bender", "rodriguez");
 246 
 247         assertEquals(table.length(), oldLength + 3); // more like an assumption
 248         int i = table.indexOf("bender", "rodriguez");
 249         assertEquals(oldLength + 1, i);
 250     }
 251 
 252     @Test
 253     public void lowerIndexPriority2() {
 254         HeaderTable table = new HeaderTable(256, HPACK.getLogger());
 255         int oldLength = table.length();
 256         int idx = rnd.nextInt(oldLength) + 1;
 257         HeaderField f = table.get(idx);
 258         table.put(f.name, f.value);
 259         assertEquals(table.length(), oldLength + 1);
 260         int i = table.indexOf(f.name, f.value);
 261         assertEquals(idx, i);
 262     }
 263 
 264     // TODO: negative indexes check
 265     // TODO: ensure full table clearance when adding huge header field
 266     // TODO: ensure eviction deletes minimum needed entries, not more
 267 
 268     @Test
 269     public void fifo() {

 270         // Let's add a series of header fields
 271         int NUM_HEADERS = 32;
 272         HeaderTable t = new HeaderTable((32 + 4) * NUM_HEADERS, HPACK.getLogger());
 273         //                                ^   ^
 274         //                   entry overhead   symbols per entry (max 2x2 digits)
 275         for (int i = 1; i <= NUM_HEADERS; i++) {
 276             String s = String.valueOf(i);
 277             t.put(s, s);
 278         }
 279         // They MUST appear in a FIFO order:
 280         //   newer entries are at lower indexes
 281         //   older entries are at higher indexes
 282         for (int j = 1; j <= NUM_HEADERS; j++) {
 283             HeaderField f = t.get(STATIC_TABLE_LENGTH + j);
 284             int actualName = Integer.parseInt(f.name);
 285             int expectedName = NUM_HEADERS - j + 1;
 286             assertEquals(expectedName, actualName);
 287         }
 288         // Entries MUST be evicted in the order they were added:
 289         //   the newer the entry the later it is evicted
 290         for (int k = 1; k <= NUM_HEADERS; k++) {
 291             HeaderField f = t.evictEntry();
 292             assertEquals(String.valueOf(k), f.name);
 293         }
 294     }
 295 
 296     @Test
 297     public void indexOf() {

 298         // Let's put a series of header fields
 299         int NUM_HEADERS = 32;
 300         HeaderTable t = new HeaderTable((32 + 4) * NUM_HEADERS, HPACK.getLogger());
 301         //                                ^   ^
 302         //                   entry overhead   symbols per entry (max 2x2 digits)
 303         for (int i = 1; i <= NUM_HEADERS; i++) {
 304             String s = String.valueOf(i);
 305             t.put(s, s);
 306         }
 307         // and verify indexOf (reverse lookup) returns correct indexes for
 308         // full lookup
 309         for (int j = 1; j <= NUM_HEADERS; j++) {
 310             String s = String.valueOf(j);
 311             int actualIndex = t.indexOf(s, s);
 312             int expectedIndex = STATIC_TABLE_LENGTH + NUM_HEADERS - j + 1;
 313             assertEquals(expectedIndex, actualIndex);
 314         }
 315         // as well as for just a name lookup
 316         for (int j = 1; j <= NUM_HEADERS; j++) {
 317             String s = String.valueOf(j);
 318             int actualIndex = t.indexOf(s, "blah");
 319             int expectedIndex = -(STATIC_TABLE_LENGTH + NUM_HEADERS - j + 1);
 320             assertEquals(expectedIndex, actualIndex);
 321         }
 322         // lookup for non-existent name returns 0
 323         assertEquals(0, t.indexOf("chupacabra", "1"));
 324     }
 325 
 326     @Test
 327     public void testToString() {
 328         testToString0();
 329     }
 330 
 331     @Test
 332     public void testToStringDifferentLocale() {
 333         Locale locale = Locale.getDefault();
 334         Locale.setDefault(Locale.FRENCH);
 335         try {
 336             String s = format("%.1f", 3.1);
 337             assertEquals("3,1", s); // assumption of the test, otherwise the test is useless
 338             testToString0();
 339         } finally {
 340             Locale.setDefault(locale);
 341         }
 342     }
 343 
 344     private void testToString0() {
 345         HeaderTable table = new HeaderTable(0, HPACK.getLogger());
 346         {
 347             int maxSize = 2048;
 348             table.setMaxSize(maxSize);
 349             String expected = format(
 350                     "dynamic length: %s, full length: %s, used space: %s/%s (%.1f%%)",
 351                     0, STATIC_TABLE_LENGTH, 0, maxSize, 0.0);
 352             assertEquals(expected, table.toString());
 353         }
 354 
 355         {
 356             String name = "custom-name";
 357             String value = "custom-value";
 358             int size = 512;
 359 
 360             table.setMaxSize(size);
 361             table.put(name, value);
 362             String s = table.toString();
 363 
 364             int used = name.length() + value.length() + 32;
 365             double ratio = used * 100.0 / size;
 366 
 367             String expected = format(
 368                     "dynamic length: %s, full length: %s, used space: %s/%s (%.1f%%)",
 369                     1, STATIC_TABLE_LENGTH + 1, used, size, ratio);
 370             assertEquals(expected, s);
 371         }
 372 
 373         {
 374             table.setMaxSize(78);
 375             table.put(":method", "");
 376             table.put(":status", "");
 377             String s = table.toString();
 378             String expected =
 379                     format("dynamic length: %s, full length: %s, used space: %s/%s (%.1f%%)",
 380                            2, STATIC_TABLE_LENGTH + 2, 78, 78, 100.0);
 381             assertEquals(expected, s);
 382         }
 383     }
 384 
 385     @Test
 386     public void stateString() {
 387         HeaderTable table = new HeaderTable(256, HPACK.getLogger());
 388         table.put("custom-key", "custom-header");
 389         // @formatter:off
 390         assertEquals("[  1] (s =  55) custom-key: custom-header\n" +
 391                      "      Table size:  55", table.getStateString());
 392         // @formatter:on
 393     }
 394 
 395     private static Map<Integer, HeaderField> createStaticEntries() {
 396         Pattern line = Pattern.compile(
 397                 "\\|\\s*(?<index>\\d+?)\\s*\\|\\s*(?<name>.+?)\\s*\\|\\s*(?<value>.*?)\\s*\\|");
 398         Matcher m = line.matcher(SPEC);
 399         Map<Integer, HeaderField> result = new HashMap<>();
 400         while (m.find()) {
 401             int index = Integer.parseInt(m.group("index"));
 402             String name = m.group("name");
 403             String value = m.group("value");
 404             HeaderField f = new HeaderField(name, value);
 405             result.put(index, f);
 406         }
 407         return Collections.unmodifiableMap(result); // lol
< prev index next >