1 /*
   2  * Copyright (c) 2018, 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  */
  23 
  24 /*
  25  * @test
  26  * @summary Tests for HttpHeaders.of factory method
  27  * @run testng HttpHeadersOf
  28  */
  29 
  30 import java.net.http.HttpHeaders;
  31 import java.util.ArrayList;
  32 import java.util.LinkedList;
  33 import java.util.List;
  34 import java.util.Map;
  35 import java.util.function.BiPredicate;
  36 import org.testng.annotations.DataProvider;
  37 import org.testng.annotations.Test;
  38 import static org.testng.Assert.assertFalse;
  39 import static org.testng.Assert.assertEquals;
  40 import static org.testng.Assert.assertThrows;
  41 import static org.testng.Assert.assertTrue;
  42 import static org.testng.Assert.fail;
  43 
  44 public class HttpHeadersOf {
  45 
  46     static final Class<NullPointerException> NPE = NullPointerException.class;
  47     static final Class<NumberFormatException> NFE = NumberFormatException.class;
  48     static final Class<UnsupportedOperationException> UOE = UnsupportedOperationException.class;
  49 
  50     static final BiPredicate<String,String> ACCEPT_ALL =
  51         new BiPredicate<>() {
  52             @Override public boolean test(String name, String value) { return true; }
  53             @Override public String toString() { return "ACCEPT_ALL"; }
  54         };
  55 
  56     static final BiPredicate<String,String> REJECT_ALL =
  57         new BiPredicate<>() {
  58             @Override public boolean test(String name, String value) { return false; }
  59             @Override public String toString() { return "REJECT_ALL"; }
  60         };
  61 
  62     @DataProvider(name = "predicates")
  63     public Object[][] predicates() {
  64         return new Object[][] { { ACCEPT_ALL }, { REJECT_ALL } };
  65     }
  66 
  67     @Test(dataProvider = "predicates")
  68     public void testNull(BiPredicate<String,String> filter) {
  69         assertThrows(NPE, () -> HttpHeaders.of(null, null));
  70         assertThrows(NPE, () -> HttpHeaders.of(null, filter));
  71         assertThrows(NPE, () -> HttpHeaders.of(Map.of(), null));
  72         assertThrows(NPE, () -> HttpHeaders.of(Map.of("name", List.of("value")), null));
  73 
  74         // nulls in the Map
  75         assertThrows(NPE, () -> HttpHeaders.of(Map.of(null, List.of("value)")), filter));
  76         assertThrows(NPE, () -> HttpHeaders.of(Map.of("name", null), filter));
  77         assertThrows(NPE, () -> HttpHeaders.of(Map.of("name", List.of(null)), filter));
  78         assertThrows(NPE, () -> HttpHeaders.of(Map.of("name", List.of("aValue", null)), filter));
  79         assertThrows(NPE, () -> HttpHeaders.of(Map.of("name", List.of(null, "aValue")), filter));
  80     }
  81 
  82 
  83     @DataProvider(name = "filterMaps")
  84     public Object[][] filterMaps() {
  85         List<Map<String, List<String>>> maps = List.of(
  86                 Map.of("A", List.of("B"),           "X", List.of("Y", "Z")),
  87                 Map.of("A", List.of("B", "C"),      "X", List.of("Y", "Z")),
  88                 Map.of("A", List.of("B", "C", "D"), "X", List.of("Y", "Z"))
  89         );
  90         return maps.stream().map(p -> new Object[] { p }).toArray(Object[][]::new);
  91     }
  92 
  93     @Test(dataProvider = "filterMaps")
  94     public void testFilter(Map<String,List<String>> map) {
  95         HttpHeaders headers = HttpHeaders.of(map, REJECT_ALL);
  96         assertEquals(headers.map().size(), 0);
  97         assertFalse(headers.firstValue("A").isPresent());
  98         assertEquals(headers.allValues("A").size(), 0);
  99 
 100         headers = HttpHeaders.of(map, (name, value) -> {
 101             if (name.equals("A")) return true; else return false; });
 102         assertEquals(headers.map().size(), 1);
 103         assertTrue(headers.firstValue("A").isPresent());
 104         assertEquals(headers.allValues("A"), map.get("A"));
 105         assertEquals(headers.allValues("A").size(), map.get("A").size());
 106         assertFalse(headers.firstValue("X").isPresent());
 107 
 108         headers = HttpHeaders.of(map, (name, value) -> {
 109             if (name.equals("X")) return true; else return false; });
 110         assertEquals(headers.map().size(), 1);
 111         assertTrue(headers.firstValue("X").isPresent());
 112         assertEquals(headers.allValues("X"), map.get("X"));
 113         assertEquals(headers.allValues("X").size(), map.get("X").size());
 114         assertFalse(headers.firstValue("A").isPresent());
 115     }
 116 
 117 
 118     @DataProvider(name = "mapValues")
 119     public Object[][] mapValues() {
 120         List<Map<String, List<String>>> maps = List.of(
 121             Map.of("A", List.of("B")),
 122             Map.of("A", List.of("B", "C")),
 123             Map.of("A", List.of("B", "C", "D")),
 124 
 125             Map.of("A", List.of("B"),           "X", List.of("Y", "Z")),
 126             Map.of("A", List.of("B", "C"),      "X", List.of("Y", "Z")),
 127             Map.of("A", List.of("B", "C", "D"), "X", List.of("Y", "Z")),
 128 
 129             Map.of("A", List.of("B"),           "X", List.of("Y", "Z")),
 130             Map.of("A", List.of("B", "C"),      "X", List.of("Y", "Z")),
 131             Map.of("A", List.of("B", "C", "D"), "X", List.of("Y", "Z")),
 132 
 133             Map.of("X", List.of("Y", "Z"), "A", List.of("B")),
 134             Map.of("X", List.of("Y", "Z"), "A", List.of("B", "C")),
 135             Map.of("X", List.of("Y", "Z"), "A", List.of("B", "C", "D"))
 136         );
 137         return maps.stream().map(p -> new Object[] { p }).toArray(Object[][]::new);
 138     }
 139 
 140     @Test(dataProvider = "mapValues")
 141     public void testMapValues(Map<String,List<String>> map) {
 142         HttpHeaders headers = HttpHeaders.of(map, ACCEPT_ALL);
 143 
 144         assertEquals(headers.map().size(), map.size());
 145         assertTrue(headers.firstValue("A").isPresent());
 146         assertTrue(headers.firstValue("a").isPresent());
 147         assertEquals(headers.firstValue("A").get(), "B");
 148         assertEquals(headers.firstValue("a").get(), "B");
 149         assertEquals(headers.allValues("A"), map.get("A"));
 150         assertEquals(headers.allValues("a"), map.get("A"));
 151         assertEquals(headers.allValues("F").size(), 0);
 152         assertTrue(headers.map().get("A").contains("B"));
 153         assertFalse(headers.map().get("A").contains("F"));
 154         assertThrows(NFE, () -> headers.firstValueAsLong("A"));
 155 
 156         // a non-exhaustive list of mutators
 157         assertThrows(UOE, () -> headers.map().put("Z", List.of("Z")));
 158         assertThrows(UOE, () -> headers.map().remove("A"));
 159         assertThrows(UOE, () -> headers.map().remove("A", "B"));
 160         assertThrows(UOE, () -> headers.map().clear());
 161         assertThrows(UOE, () -> headers.allValues("A").remove("B"));
 162         assertThrows(UOE, () -> headers.allValues("A").remove(1));
 163         assertThrows(UOE, () -> headers.allValues("A").clear());
 164         assertThrows(UOE, () -> headers.allValues("A").add("Z"));
 165         assertThrows(UOE, () -> headers.allValues("A").addAll(List.of("Z")));
 166         assertThrows(UOE, () -> headers.allValues("A").add(1, "Z"));
 167     }
 168 
 169 
 170     @DataProvider(name = "caseInsensitivity")
 171     public Object[][] caseInsensitivity() {
 172         List<Map<String, List<String>>> maps = List.of(
 173              Map.of("Accept-Encoding", List.of("gzip, deflate")),
 174              Map.of("accept-encoding", List.of("gzip, deflate")),
 175              Map.of("AccePT-ENCoding", List.of("gzip, deflate")),
 176              Map.of("ACCept-EncodING", List.of("gzip, deflate")),
 177              Map.of("ACCEPT-ENCODING", List.of("gzip, deflate"))
 178         );
 179         return maps.stream().map(p -> new Object[] { p }).toArray(Object[][]::new);
 180     }
 181 
 182     @Test(dataProvider = "caseInsensitivity")
 183     public void testCaseInsensitivity(Map<String,List<String>> map) {
 184         HttpHeaders headers = HttpHeaders.of(map, ACCEPT_ALL);
 185 
 186         for (String name : List.of("Accept-Encoding", "accept-encoding",
 187                                    "aCCept-EnCODing", "accepT-encodinG")) {
 188             assertTrue(headers.firstValue(name).isPresent());
 189             assertTrue(headers.allValues(name).contains("gzip, deflate"));
 190             assertEquals(headers.firstValue(name).get(), "gzip, deflate");
 191             assertEquals(headers.allValues(name).size(), 1);
 192             assertEquals(headers.map().size(), 1);
 193             assertEquals(headers.map().get(name).size(), 1);
 194             assertEquals(headers.map().get(name).get(0), "gzip, deflate");
 195         }
 196     }
 197 
 198     @DataProvider(name = "valueAsLong")
 199     public Object[][] valueAsLong() {
 200         return new Object[][] {
 201             new Object[] { Map.of("Content-Length", List.of("10")), 10l },
 202             new Object[] { Map.of("Content-Length", List.of("101")), 101l },
 203             new Object[] { Map.of("Content-Length", List.of("56789")), 56789l },
 204             new Object[] { Map.of("Content-Length", List.of(Long.toString(Long.MAX_VALUE))), Long.MAX_VALUE },
 205             new Object[] { Map.of("Content-Length", List.of(Long.toString(Long.MIN_VALUE))), Long.MIN_VALUE }
 206         };
 207     }
 208 
 209     @Test(dataProvider = "valueAsLong")
 210     public void testValueAsLong(Map<String,List<String>> map, long expected) {
 211         HttpHeaders headers = HttpHeaders.of(map, ACCEPT_ALL);
 212         assertEquals(headers.firstValueAsLong("Content-Length").getAsLong(), expected);
 213     }
 214 
 215 
 216     @DataProvider(name = "duplicateNames")
 217     public Object[][] duplicateNames() {
 218         List<Map<String, List<String>>> maps = List.of(
 219                 Map.of("X-name", List.of(),
 220                        "x-name", List.of()),
 221                 Map.of("X-name", List.of(""),
 222                        "x-name", List.of("")),
 223                 Map.of("X-name", List.of("C"),
 224                        "x-name", List.of("D")),
 225                 Map.of("X-name", List.of("E"),
 226                        "Y-name", List.of("F"),
 227                        "X-Name", List.of("G")),
 228                 Map.of("X-chegar", List.of("H"),
 229                        "y-dfuchs", List.of("I"),
 230                        "Y-dfuchs", List.of("J")),
 231                 Map.of("X-name ", List.of("K"),
 232                        "X-Name", List.of("L")),
 233                 Map.of("X-name", List.of("M"),
 234                        "\rX-Name", List.of("N"))
 235         );
 236         return maps.stream().map(p -> new Object[] { p }).toArray(Object[][]::new);
 237     }
 238 
 239     @Test(dataProvider = "duplicateNames")
 240     public void testDuplicates(Map<String,List<String>> map) {
 241         HttpHeaders headers;
 242         try {
 243             headers = HttpHeaders.of(map, ACCEPT_ALL);
 244             fail("UNEXPECTED: " + headers);
 245         } catch (IllegalArgumentException iae) {
 246             System.out.println("caught EXPECTED IAE:" + iae);
 247             assertTrue(iae.getMessage().contains("duplicate"));
 248         }
 249     }
 250 
 251 
 252     @DataProvider(name = "noSplittingJoining")
 253     public Object[][] noSplittingJoining() {
 254         List<Map<String, List<String>>> maps = List.of(
 255                 Map.of("A", List.of("B")),
 256                 Map.of("A", List.of("B", "C")),
 257                 Map.of("A", List.of("B", "C", "D")),
 258                 Map.of("A", List.of("B", "C", "D", "E")),
 259                 Map.of("A", List.of("B", "C", "D", "E", "F")),
 260                 Map.of("A", List.of("B, C")),
 261                 Map.of("A", List.of("B, C, D")),
 262                 Map.of("A", List.of("B, C, D, E")),
 263                 Map.of("A", List.of("B, C, D, E, F")),
 264                 Map.of("A", List.of("B, C", "D", "E", "F")),
 265                 Map.of("A", List.of("B", "C, D", "E", "F")),
 266                 Map.of("A", List.of("B", "C, D", "E, F")),
 267                 Map.of("A", List.of("B", "C, D, E", "F")),
 268                 Map.of("A", List.of("B", "C, D, E, F"))
 269         );
 270         return maps.stream().map(p -> new Object[] { p }).toArray(Object[][]::new);
 271     }
 272 
 273     @Test(dataProvider = "noSplittingJoining")
 274     public void testNoSplittingJoining(Map<String,List<String>> map) {
 275         HttpHeaders headers = HttpHeaders.of(map, ACCEPT_ALL);
 276         Map<String,List<String>> headersMap = headers.map();
 277 
 278         assertEquals(headers.map().size(), map.size());
 279         for (Map.Entry<String,List<String>> entry : map.entrySet()) {
 280             String headerName = entry.getKey();
 281             List<String> headerValues = entry.getValue();
 282             assertEquals(headerValues, headersMap.get(headerName));
 283             assertEquals(headerValues, headers.allValues(headerName));
 284             assertEquals(headerValues.get(0), headers.firstValue(headerName).get());
 285         }
 286     }
 287 
 288 
 289     @DataProvider(name = "trimming")
 290     public Object[][] trimming() {
 291         List<Map<String, List<String>>> maps = List.of(
 292                 Map.of("A", List.of("B")),
 293                 Map.of(" A", List.of("B")),
 294                 Map.of("A ", List.of("B")),
 295                 Map.of("A", List.of(" B")),
 296                 Map.of("A", List.of("B ")),
 297                 Map.of("\tA", List.of("B")),
 298                 Map.of("A\t", List.of("B")),
 299                 Map.of("A", List.of("\tB")),
 300                 Map.of("A", List.of("B\t")),
 301                 Map.of("A\r", List.of("B")),
 302                 Map.of("A\n", List.of("B")),
 303                 Map.of("A\r\n", List.of("B"))
 304         );
 305         return maps.stream().map(p -> new Object[] { p }).toArray(Object[][]::new);
 306     }
 307 
 308     @Test(dataProvider = "trimming")
 309     public void testTrimming(Map<String,List<String>> map) {
 310         HttpHeaders headers = HttpHeaders.of(map, (name, value) -> {
 311             assertEquals(name, "A");
 312             assertEquals(value, "B");
 313             return true;
 314         });
 315 
 316         assertEquals(headers.map().size(), 1);
 317         assertEquals(headers.firstValue("A").get(), "B");
 318         assertEquals(headers.allValues("A"), List.of("B"));
 319         assertTrue(headers.map().get("A").equals(List.of("B")));
 320     }
 321 
 322 
 323     @DataProvider(name = "emptyKey")
 324     public Object[][] emptyKey() {
 325         List<Map<String, List<String>>> maps = List.of(
 326                 Map.of("", List.of("B")),
 327                 Map.of(" ", List.of("B")),
 328                 Map.of("  ", List.of("B")),
 329                 Map.of("\t", List.of("B")),
 330                 Map.of("\t\t", List.of("B"))
 331         );
 332         return maps.stream().map(p -> new Object[] { p }).toArray(Object[][]::new);
 333     }
 334 
 335     @Test(dataProvider = "emptyKey")
 336     public void testEmptyKey(Map<String,List<String>> map) {
 337         HttpHeaders headers;
 338         try {
 339             headers = HttpHeaders.of(map, ACCEPT_ALL);
 340             fail("UNEXPECTED: " + headers);
 341         } catch (IllegalArgumentException iae) {
 342             System.out.println("caught EXPECTED IAE:" + iae);
 343             assertTrue(iae.getMessage().contains("empty"));
 344         }
 345     }
 346 
 347 
 348     @DataProvider(name = "emptyValue")
 349     public Object[][] emptyValue() {
 350         List<Map<String, List<String>>> maps = List.of(
 351                 Map.of("A", List.of("")),
 352                 Map.of("A", List.of("", "")),
 353                 Map.of("A", List.of("", "", " ")),
 354                 Map.of("A", List.of("\t")),
 355                 Map.of("A", List.of("\t\t"))
 356         );
 357         return maps.stream().map(p -> new Object[] { p }).toArray(Object[][]::new);
 358     }
 359 
 360     @Test(dataProvider = "emptyValue")
 361     public void testEmptyValue(Map<String,List<String>> map) {
 362         HttpHeaders headers = HttpHeaders.of(map, (name, value) -> {
 363             assertEquals(value, "");
 364             return true;
 365         });
 366         assertEquals(headers.map().size(), map.size());
 367         assertEquals(headers.map().get("A").get(0), "");
 368         headers.allValues("A").forEach(v -> assertEquals(v, ""));
 369         assertEquals(headers.firstValue("A").get(), "");
 370     }
 371 
 372 
 373     @DataProvider(name = "noValues")
 374     public Object[][] noValues() {
 375         List<Map<String, List<String>>> maps = List.of(
 376                 Map.of("A", List.of()),
 377                 Map.of("A", List.of(), "B", List.of()),
 378                 Map.of("A", List.of(), "B", List.of(), "C", List.of()),
 379                 Map.of("A", new ArrayList()),
 380                 Map.of("A", new LinkedList())
 381         );
 382         return maps.stream().map(p -> new Object[] { p }).toArray(Object[][]::new);
 383     }
 384 
 385     @Test(dataProvider = "noValues")
 386     public void testNoValues(Map<String,List<String>> map) {
 387         HttpHeaders headers = HttpHeaders.of(map, (name, value) -> {
 388             fail("UNEXPECTED call to filter");
 389             return true;
 390         });
 391         assertEquals(headers.map().size(), 0);
 392         assertEquals(headers.map().get("A"), null);
 393         assertEquals(headers.allValues("A").size(), 0);
 394         assertFalse(headers.firstValue("A").isPresent());
 395     }
 396 }