code: // Licensed to the Software Freedom Conservancy (SFC) under one
  // or more contributor license agreements.  See the NOTICE file
  // distributed with this work for additional information
  // regarding copyright ownership.  The SFC licenses this file
  // to you 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 org.openqa.selenium.remote;
  
  import static java.util.Arrays.asList;
  import static java.util.Collections.EMPTY_MAP;
  import static java.util.Collections.emptyMap;
  import static java.util.Collections.singleton;
  import static java.util.Collections.singletonList;
  import static java.util.Collections.singletonMap;
  import static java.util.stream.Collectors.toList;
  import static org.assertj.core.api.Assertions.assertThat;
  import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
  import static org.junit.jupiter.api.Assertions.assertEquals;
  import static org.junit.jupiter.api.Assertions.assertNull;
  import static org.openqa.selenium.json.Json.MAP_TYPE;
  
  import com.google.common.collect.ImmutableMap;
  import java.io.IOException;
  import java.io.StringReader;
  import java.util.HashMap;
  import java.util.List;
  import java.util.Map;
  import org.junit.jupiter.api.Tag;
  import org.junit.jupiter.api.Test;
  import org.openqa.selenium.Capabilities;
  import org.openqa.selenium.ImmutableCapabilities;
  import org.openqa.selenium.Platform;
  import org.openqa.selenium.json.Json;
  
  @Tag("UnitTests")
  class NewSessionPayloadTest {
  
    @Test
    void shouldIndicateDownstreamW3cDialect() {
      Map<String, Map<String, Map<String, String>>> caps =
          singletonMap(
              "capabilities", singletonMap("alwaysMatch", singletonMap("browserName", "cheese")));
  
      try (NewSessionPayload payload = NewSessionPayload.create(caps)) {
        assertEquals(singleton(Dialect.W3C), payload.getDownstreamDialects());
      }
  
      String json = new Json().toJson(caps);
      try (NewSessionPayload payload = NewSessionPayload.create(new StringReader(json))) {
        assertEquals(singleton(Dialect.W3C), payload.getDownstreamDialects());
      }
    }
  
    @Test
    void shouldReturnAlwaysMatchIfNoFirstMatchIsPresent() {
      List<Capabilities> capabilities =
          create(
              singletonMap(
                  "capabilities",
                  singletonMap("alwaysMatch", singletonMap("browserName", "cheese"))));
  
      assertEquals(1, capabilities.size(), capabilities.toString());
      assertEquals("cheese", capabilities.get(0).getBrowserName());
    }
  
    @Test
    void shouldReturnEachFirstMatchIfNoAlwaysMatchIsPresent() {
      List<Capabilities> capabilities =
          create(
              singletonMap(
                  "capabilities",
                  singletonMap(
                      "firstMatch",
                      asList(
                          singletonMap("browserName", "cheese"),
                          singletonMap("browserName", "peas")))));
  
      assertEquals(2, capabilities.size(), capabilities.toString());
      assertEquals("cheese", capabilities.get(0).getBrowserName());
      assertEquals("peas", capabilities.get(1).getBrowserName());
    }
  
    @Test
    void shouldOfferStreamOfW3cCapabilitiesIfPresent() {
      List<Capabilities> capabilities =
          create(
              ImmutableMap.of(
                  "capabilities", singletonMap("alwaysMatch", singletonMap("browserName", "peas"))));
  
      // We expect a synthetic w3c capability for the mismatching OSS capabilities
      assertEquals(1, capabilities.size(), capabilities.toString());
      assertEquals("peas", capabilities.get(0).getBrowserName());
    }
  
    @Test
    void shouldMergeAlwaysAndFirstMatches() {
      List<Capabilities> capabilities =
          create(
              singletonMap(
                  "capabilities",
                  ImmutableMap.of(
                      "alwaysMatch", singletonMap("se:cake", "also cheese"),
                      "firstMatch",
                          asList(
                              singletonMap("browserName", "cheese"),
                              singletonMap("browserName", "peas")))));
  
      assertEquals(2, capabilities.size(), capabilities.toString());
      assertEquals("cheese", capabilities.get(0).getBrowserName());
      assertEquals("also cheese", capabilities.get(0).getCapability("se:cake"));
      assertEquals("peas", capabilities.get(1).getBrowserName());
      assertEquals("also cheese", capabilities.get(1).getCapability("se:cake"));
    }
  
    @Test
    void shouldCorrectlyExtractPlatformFromW3cCapabilities() {
      List<Capabilities> capabilities =
          create(
              singletonMap(
                  "capabilities",
                  singletonMap("alwaysMatch", singletonMap("platformName", "linux"))));
  
      assertEquals(Platform.LINUX, capabilities.get(0).getPlatformName());
    }
  
    @Test
    void shouldValidateW3cCapabilitiesByComplainingAboutKeysThatAreNotExtensions() {
      assertThatExceptionOfType(IllegalArgumentException.class)
          .isThrownBy(
              () ->
                  create(
                      singletonMap(
                          "capabilities",
                          singletonMap("alwaysMatch", singletonMap("cake", "cheese")))));
    }
  
    @Test
    void shouldValidateW3cCapabilitiesByComplainingAboutDuplicateFirstAndAlwaysMatchKeys() {
      assertThatExceptionOfType(IllegalArgumentException.class)
          .isThrownBy(
              () ->
                  create(
                      singletonMap(
                          "capabilities",
                          ImmutableMap.of(
                              "alwaysMatch", singletonMap("se:cake", "cheese"),
                              "firstMatch", singletonList(singletonMap("se:cake", "sausages"))))));
    }
  
    @Test
    void convertEverythingToFirstMatchOnlyIfPayloadContainsAlwaysMatchSectionAndOssCapabilities() {
      List<Capabilities> capabilities =
          create(
              ImmutableMap.of(
                  "capabilities",
                  ImmutableMap.of(
                      "alwaysMatch", singletonMap("platformName", "macos"),
                      "firstMatch",
                          asList(
                              singletonMap("browserName", "foo"),
                              singletonMap("browserName", "firefox")))));
  
      assertEquals(
          asList(
              // From the actual W3C capabilities
              new ImmutableCapabilities("browserName", "foo", "platformName", "macos"),
              new ImmutableCapabilities("browserName", "firefox", "platformName", "macos")),
          capabilities);
    }
  
    @Test
    void forwardsMetaDataAssociatedWithARequest() throws IOException {
      try (NewSessionPayload payload =
          NewSessionPayload.create(
              ImmutableMap.of(
                  "capabilities", ImmutableMap.of("alwaysMatch", EMPTY_MAP),
                  "cloud:user", "bob",
                  "cloud:key", "there is no cake"))) {
        StringBuilder toParse = new StringBuilder();
        payload.writeTo(toParse);
        Map<String, Object> seen = new Json().toType(toParse.toString(), MAP_TYPE);
  
        assertEquals("bob", seen.get("cloud:user"));
        assertEquals("there is no cake", seen.get("cloud:key"));
      }
    }
  
    @Test
    void doesNotForwardRequiredCapabilitiesAsTheseAreVeryLegacy() throws IOException {
      try (NewSessionPayload payload =
          NewSessionPayload.create(
              ImmutableMap.of(
                  "capabilities",
                  EMPTY_MAP,
                  "requiredCapabilities",
                  singletonMap("key", "so it's not empty")))) {
        StringBuilder toParse = new StringBuilder();
        payload.writeTo(toParse);
        Map<String, Object> seen = new Json().toType(toParse.toString(), MAP_TYPE);
  
        assertNull(seen.get("requiredCapabilities"));
      }
    }
  
    @Test
    void shouldPreserveMetadata() throws IOException {
      Map<String, Object> raw =
          ImmutableMap.of(
              "capabilities",
              singletonMap("alwaysMatch", singletonMap("browserName", "cheese")),
              "se:meta",
              "cheese is good");
  
      try (NewSessionPayload payload = NewSessionPayload.create(raw)) {
        StringBuilder toParse = new StringBuilder();
        payload.writeTo(toParse);
        Map<String, Object> seen = new Json().toType(toParse.toString(), MAP_TYPE);
  
        assertThat(seen).containsEntry("se:meta", "cheese is good");
      }
    }
  
    @Test
    void shouldExposeMetaData() {
      Map<String, Object> raw =
          ImmutableMap.of(
              "capabilities",
              singletonMap("alwaysMatch", singletonMap("browserName", "cheese")),
              "se:meta",
              "cheese is good");
  
      try (NewSessionPayload payload = NewSessionPayload.create(raw)) {
        Map<String, Object> seen = payload.getMetadata();
        assertThat(seen).isEqualTo(Map.of("se:meta", "cheese is good"));
      }
    }
  
    @Test
    void nullValuesInMetaDataAreIgnored() {
      Map<String, Object> raw = new HashMap<>();
      raw.put("capabilities", singletonMap("alwaysMatch", singletonMap("browserName", "cheese")));
      raw.put("se:bad", null);
      raw.put("se:good", "cheese");
  
      try (NewSessionPayload payload = NewSessionPayload.create(raw)) {
        Map<String, Object> seen = payload.getMetadata();
        assertThat(seen).isEqualTo(Map.of("se:good", "cheese"));
      }
    }
  
    @Test
    void keysUsedForStoringCapabilitiesAreIgnoredFromMetadata() {
      Map<String, Object> raw =
          ImmutableMap.of(
              "capabilities", singletonMap("alwaysMatch", singletonMap("browserName", "cheese")),
              "desiredCapabilities", emptyMap());
  
      try (NewSessionPayload payload = NewSessionPayload.create(raw)) {
        Map<String, Object> seen = payload.getMetadata();
        assertThat(seen).isEqualTo(emptyMap());
      }
    }
  
    private List<Capabilities> create(Map<String, ?> source) {
      List<Capabilities> presumablyFromMemory;
      List<Capabilities> fromDisk;
  
      try (NewSessionPayload payload = NewSessionPayload.create(source)) {
        presumablyFromMemory = payload.stream().collect(toList());
      }
  
      String json = new Json().toJson(source);
      try (NewSessionPayload payload = NewSessionPayload.create(new StringReader(json))) {
        fromDisk = payload.stream().collect(toList());
      }
  
      assertEquals(presumablyFromMemory, fromDisk);
  
      return presumablyFromMemory;
    }
  }
  