blob: 0588393ef8b095f52c23ea367045d918d912235d [file] [log] [blame]
// Copyright 2020 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "typecd/port.h"
#include <string>
#include <base/files/scoped_temp_dir.h>
#include <base/strings/stringprintf.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "typecd/pd_vdo_constants.h"
#include "typecd/test_constants.h"
#include "typecd/test_utils.h"
namespace {
constexpr char kInvalidDataRole1[] = "xsadft [hasdr]";
constexpr char kInvalidDataRole2[] = "]asdf[ dsdd";
constexpr char kValidDataRole1[] = "device";
constexpr char kValidDataRole2[] = "[host] device";
constexpr char kValidDataRole3[] = "host [device]";
constexpr char kValidPowerRole1[] = "[source] sink";
constexpr char kValidPowerRole2[] = "source [sink]";
constexpr char kInvalidPowerRole1[] = "asdf#//%sxdfa";
constexpr char kValidPanel[] = "left";
constexpr char kInvalidPanel[] = "asdf";
constexpr char kValidHorizontalPosition[] = "right";
constexpr char kInvalidHorizontalPosition[] = "fdas";
constexpr char kValidVerticalPosition[] = "upper";
constexpr char kInvalidVerticalPosition[] = "dsaf";
} // namespace
namespace typecd {
class PortTest : public ::testing::Test {
protected:
void SetUp() override {
ASSERT_TRUE(scoped_temp_dir_.CreateUniqueTempDir());
temp_dir_ = scoped_temp_dir_.GetPath();
}
public:
base::FilePath temp_dir_;
base::ScopedTempDir scoped_temp_dir_;
};
// Check that basic Port creation, partner addition/deletion works.
TEST_F(PortTest, BasicAdd) {
auto port = std::make_unique<Port>(base::FilePath(kFakePort0SysPath), 0);
EXPECT_NE(nullptr, port);
port->AddPartner(base::FilePath(kFakePort0PartnerSysPath));
EXPECT_NE(nullptr, port->partner_);
port->RemovePartner();
EXPECT_EQ(nullptr, port->partner_);
}
// Check GetDataRole() for various sysfs values.
TEST_F(PortTest, GetDataRole) {
// Set up fake sysfs directory for the port..
auto port_path = temp_dir_.Append("port0");
ASSERT_TRUE(base::CreateDirectory(port_path));
auto data_role_path = port_path.Append("data_role");
ASSERT_TRUE(base::WriteFile(data_role_path, kValidDataRole1,
strlen(kValidDataRole1)));
// Create a port.
auto port = std::make_unique<Port>(base::FilePath(port_path), 0);
ASSERT_NE(nullptr, port);
EXPECT_EQ(DataRole::kDevice, port->GetDataRole());
ASSERT_TRUE(base::WriteFile(data_role_path, kValidDataRole2,
strlen(kValidDataRole2)));
// Fake a port changed event.
port->PortChanged();
EXPECT_EQ(DataRole::kHost, port->GetDataRole());
ASSERT_TRUE(base::WriteFile(port_path.Append("data_role"), kValidDataRole3,
strlen(kValidDataRole3)));
// Fake a port changed event.
port->PortChanged();
EXPECT_EQ(DataRole::kDevice, port->GetDataRole());
ASSERT_TRUE(base::WriteFile(port_path.Append("data_role"), kInvalidDataRole1,
strlen(kInvalidDataRole1)));
// Fake a port changed event.
port->PortChanged();
EXPECT_EQ(DataRole::kNone, port->GetDataRole());
ASSERT_TRUE(base::WriteFile(port_path.Append("data_role"), kInvalidDataRole2,
strlen(kInvalidDataRole2)));
// Fake a port changed event.
port->PortChanged();
EXPECT_EQ(DataRole::kNone, port->GetDataRole());
}
// Check GetPowerRole() for various sysfs values.
TEST_F(PortTest, GetPowerRole) {
// Set up fake sysfs directory for the port..
auto port_path = temp_dir_.Append("port0");
ASSERT_TRUE(base::CreateDirectory(port_path));
auto data_role_path = port_path.Append("power_role");
ASSERT_TRUE(base::WriteFile(data_role_path, kValidPowerRole1,
strlen(kValidPowerRole1)));
// Create a port.
auto port = std::make_unique<Port>(base::FilePath(port_path), 0);
ASSERT_NE(nullptr, port);
EXPECT_EQ(PowerRole::kSource, port->GetPowerRole());
ASSERT_TRUE(base::WriteFile(data_role_path, kValidPowerRole2,
strlen(kValidPowerRole2)));
// Fake a port changed event.
port->PortChanged();
EXPECT_EQ(PowerRole::kSink, port->GetPowerRole());
ASSERT_TRUE(base::WriteFile(data_role_path, kInvalidPowerRole1,
strlen(kInvalidPowerRole1)));
// Fake a port changed event.
port->PortChanged();
EXPECT_EQ(PowerRole::kNone, port->GetPowerRole());
}
// Check that DP Alt Mode Entry checks work as expected for a true case:
TEST_F(PortTest, DPAltModeEntryCheckTrue) {
auto port = std::make_unique<Port>(base::FilePath(kFakePort0SysPath), 0);
port->AddPartner(base::FilePath(kFakePort0PartnerSysPath));
// Set up fake sysfs paths for 1 alt mode.
// Set the number of alt modes supported.
port->partner_->SetNumAltModes(1);
// Add the DP alt mode.
std::string mode0_dirname =
base::StringPrintf("port%d-partner.%d", 0, kDPAltModeIndex);
auto mode0_path = temp_dir_.Append(mode0_dirname);
ASSERT_TRUE(CreateFakeAltMode(mode0_path, kDPAltModeSID, kDPVDO_WD19TB,
kDPVDOIndex_WD19TB));
port->AddRemovePartnerAltMode(mode0_path, true);
AddAnkerUSB3p2Gen2Cable(*port);
bool invalid_dpalt_cable = false;
EXPECT_TRUE(port->CanEnterDPAltMode(&invalid_dpalt_cable));
EXPECT_FALSE(invalid_dpalt_cable);
}
// Check that DP Alt Mode Entry checks work as expected for a specific false
// case: The Startech dock DP VDO doesn't advertise DFP_D, so we *shouldn't*
// enter DP alternate mode, despite it supporting the DP SID.
TEST_F(PortTest, DPAltModeEntryCheckFalseWithDPSID) {
auto port = std::make_unique<Port>(base::FilePath(kFakePort0SysPath), 0);
AddStartechDock(*port);
bool invalid_dpalt_cable = false;
EXPECT_FALSE(port->CanEnterDPAltMode(&invalid_dpalt_cable));
EXPECT_FALSE(invalid_dpalt_cable);
}
// Check that DP Alt Mode Entry checks work as expected for false cases.
TEST_F(PortTest, DPAltModeEntryCheckFalse) {
auto port = std::make_unique<Port>(base::FilePath(kFakePort0SysPath), 0);
port->AddPartner(base::FilePath(kFakePort0PartnerSysPath));
port->partner_->SetNumAltModes(0);
// Check the case where the partner doesn't support any alt modes.
EXPECT_FALSE(port->CanEnterDPAltMode(nullptr));
port->partner_->SetNumAltModes(1);
// Set up fake sysfs paths for 1 alt mode.
// Add the TBT alt mode.
std::string mode_dirname = base::StringPrintf("port%d-partner.%d", 0, 0);
auto mode_path = temp_dir_.Append(mode_dirname);
ASSERT_TRUE(
CreateFakeAltMode(mode_path, kTBTAltModeVID, kTBTVDO, kTBTVDOIndex));
port->AddRemovePartnerAltMode(mode_path, true);
EXPECT_FALSE(port->CanEnterDPAltMode(nullptr));
}
// Check that DP Alt Mode work as expected when one alt mode is a nullptr.
TEST_F(PortTest, DPAltModeEntryCheckTrueOneAltModeIsNullptr) {
auto port = std::make_unique<Port>(base::FilePath(kFakePort0SysPath), 0);
// Set number of alt modes to 2
port->AddPartner(base::FilePath(kFakePort0PartnerSysPath));
port->partner_->SetNumAltModes(2);
// Set up fake sysfs paths for DP alt mode, the other mode is left empty
std::string mode0_dirname =
base::StringPrintf("port%d-partner.%d", 0, kDPAltModeIndex);
auto mode0_path = temp_dir_.Append(mode0_dirname);
ASSERT_TRUE(CreateFakeAltMode(mode0_path, kDPAltModeSID, kDPVDO_WD19TB,
kDPVDOIndex_WD19TB));
port->AddRemovePartnerAltMode(mode0_path, true);
AddAnkerUSB3p2Gen2Cable(*port);
bool invalid_dpalt_cable = false;
EXPECT_TRUE(port->CanEnterDPAltMode(&invalid_dpalt_cable));
EXPECT_FALSE(invalid_dpalt_cable);
}
// Check that DP Alt Mode entry checks don't mistake the partner for
// a receptacle based on other alt mode VDOs
TEST_F(PortTest, DPAltModeEntryCheckPartnerIsReceptacle) {
auto port = std::make_unique<Port>(base::FilePath(kFakePort0SysPath), 0);
// Set number of alt modes to 2
port->AddPartner(base::FilePath(kFakePort0PartnerSysPath));
port->partner_->SetNumAltModes(2);
// Add the DP alt mode.
std::string mode0_dirname =
base::StringPrintf("port%d-partner.%d", 0, kDPAltModeIndex);
auto mode0_path = temp_dir_.Append(mode0_dirname);
ASSERT_TRUE(CreateFakeAltMode(mode0_path, kDPAltModeSID, kDPVDO_WD19TB,
kDPVDOIndex_WD19TB));
port->AddRemovePartnerAltMode(mode0_path, true);
// Add non DP alt mode with bit corresponding to kDPModeReceptacle set to 1
std::string mode1_dirname =
base::StringPrintf("port%d-partner.%d", 0, kTBTAltModeIndex);
auto mode1_path = temp_dir_.Append(mode1_dirname);
ASSERT_TRUE(CreateFakeAltMode(mode1_path, kTBTAltModeVID,
kTBTVDO | kDPModeReceptacle, kTBTVDOIndex));
port->AddRemovePartnerAltMode(mode1_path, true);
bool invalid_dpalt_cable = false;
EXPECT_TRUE(port->CanEnterDPAltMode(&invalid_dpalt_cable));
EXPECT_FALSE(invalid_dpalt_cable);
}
// Check that DP Alt Mode Entry works with cable check for a passing case.
// Case: The WIMAXIT Type-C display supports DP alternate mode and the CalDigit
// TBT4 cable supports up to USB4 so it should enter DP alternate mode and the
// cable will not be flagged as invalid
TEST_F(PortTest, DPAltModeEntryCalDigitTBT4ToDisplay) {
auto port = std::make_unique<Port>(base::FilePath(kFakePort0SysPath), 0);
AddWimaxitDisplay(*port);
AddCalDigitTBT4Cable(*port);
bool invalid_dpalt_cable = false;
EXPECT_TRUE(port->CanEnterDPAltMode(&invalid_dpalt_cable));
EXPECT_FALSE(invalid_dpalt_cable);
}
// Check that DP Alt Mode Entry works with cable check for a passing case.
// Case: The WIMAXIT Type-C display supports DP alternate mode and the Anker
// USB3.2 Gen2 cable supports USB3 so it should enter DP alternate mode and
// the cable will not be flagged as invalid
TEST_F(PortTest, DPAltModeEntryAnkerUsb3Gen2ToDisplay) {
auto port = std::make_unique<Port>(base::FilePath(kFakePort0SysPath), 0);
AddWimaxitDisplay(*port);
AddAnkerUSB3p2Gen2Cable(*port);
bool invalid_dpalt_cable = false;
EXPECT_TRUE(port->CanEnterDPAltMode(&invalid_dpalt_cable));
EXPECT_FALSE(invalid_dpalt_cable);
}
// Check that DP Alt Mode Entry works with cable check for a passing case.
// Case: The WIMAXIT Type-C display supports DP alternate mode and the HP
// USB3.2 Gen1 cable supports up to USB3.2 Gen1 so it should enter DP
// alternate mode and the cable will not be flagged as invalid
TEST_F(PortTest, DPAltModeEntryHPUsb3Gen1ToDisplay) {
auto port = std::make_unique<Port>(base::FilePath(kFakePort0SysPath), 0);
AddWimaxitDisplay(*port);
AddHPUSB3p2Gen1Cable(*port);
bool invalid_dpalt_cable = false;
EXPECT_TRUE(port->CanEnterDPAltMode(&invalid_dpalt_cable));
EXPECT_FALSE(invalid_dpalt_cable);
}
// Check that DP Alt Mode Entry works with cable check for a passing case.
// Case: The WIMAXIT Type-C display supports DP alternate mode and the Apple
// TBT3 Pro cable supports up to USB4 so it should enter DP alternate mode
// and the cable will not be flagged as invalid
TEST_F(PortTest, DPAltModeEntryAppleTBT3ToDisplay) {
auto port = std::make_unique<Port>(base::FilePath(kFakePort0SysPath), 0);
AddWimaxitDisplay(*port);
AddAppleTBT3ProCable(*port);
bool invalid_dpalt_cable = false;
EXPECT_TRUE(port->CanEnterDPAltMode(&invalid_dpalt_cable));
EXPECT_FALSE(invalid_dpalt_cable);
}
// Check that DP Alt Mode Entry works with cable check for a failing case.
// Case: The WIMAXIT Type-C display supports DP alternate mode but, an unbranded
// USB2 cable is not considered as a cable object in typecd. It should still try
// to enter alternate mode but the cable will be flagged as invalid
TEST_F(PortTest, DPAltModeEntryUnbrandedUSB2ToDisplay) {
auto port = std::make_unique<Port>(base::FilePath(kFakePort0SysPath), 0);
AddWimaxitDisplay(*port);
AddUnbrandedUSB2Cable(*port);
bool invalid_dpalt_cable = false;
EXPECT_TRUE(port->CanEnterDPAltMode(&invalid_dpalt_cable));
EXPECT_TRUE(invalid_dpalt_cable);
}
// Check that DP Alt Mode Entry works with cable check for a failing case.
// Case: The WIMAXIT Type-C display supports DP alternate mode but, a tested
// Nekteck cable only supports USB 2.0. For an emarked USB 2.0 only cable,
// typecd will not enter DPAltMode and warn the user about the cable.
TEST_F(PortTest, DPAltModeEntryNekteckUSB2ToDisplay) {
auto port = std::make_unique<Port>(base::FilePath(kFakePort0SysPath), 0);
AddWimaxitDisplay(*port);
AddNekteckUSB2PassiveCable(*port);
bool invalid_dpalt_cable = false;
EXPECT_FALSE(port->CanEnterDPAltMode(&invalid_dpalt_cable));
EXPECT_TRUE(invalid_dpalt_cable);
}
// Check that DP Alt Mode Entry works with cable check for a passing case.
// Case: The Thinkpad Dock supports DP alternate mode and a tested unbranded
// TBT3 cable supports up to USB3.2 Gen2 so it should enter DP alternate mode
// and the cable will not be flagged as invalid
TEST_F(PortTest, DPAltModeEntryTBT3ToDock) {
auto port = std::make_unique<Port>(base::FilePath(kFakePort0SysPath), 0);
AddThinkpadTBT3Dock(*port);
AddUnbrandedTBT3Cable(*port);
bool invalid_dpalt_cable = false;
EXPECT_TRUE(port->CanEnterDPAltMode(&invalid_dpalt_cable));
EXPECT_FALSE(invalid_dpalt_cable);
}
// Check that DP Alt Mode Entry works with cable check for a failing case.
// Case: The Thinkpad Dock supports DP alternate mode but a tested unbranded
// USB2 cable is not recognized by the typec daemon. It should try to enter
// DP alternate mode but the cable will be flagged as invalid.
TEST_F(PortTest, DPAltModeEntryUnbrandedUSB2ToDock) {
auto port = std::make_unique<Port>(base::FilePath(kFakePort0SysPath), 0);
AddThinkpadTBT3Dock(*port);
AddUnbrandedUSB2Cable(*port);
bool invalid_dpalt_cable = false;
EXPECT_TRUE(port->CanEnterDPAltMode(&invalid_dpalt_cable));
EXPECT_TRUE(invalid_dpalt_cable);
}
// Check that DP Alt Mode Entry works with cable check for a failing case.
// Case: The Thinkpad Dock supports DP alternate mode but a tested Nekteck
// type-c cable only supports USB 2.0. For an emarked USB 2.0 only cable,
// typecd will not enter DPAltMode and warn the user about the cable.
TEST_F(PortTest, DPAltModeEntryNekteckUSB2ToDock) {
auto port = std::make_unique<Port>(base::FilePath(kFakePort0SysPath), 0);
AddThinkpadTBT3Dock(*port);
AddNekteckUSB2PassiveCable(*port);
bool invalid_dpalt_cable = false;
EXPECT_FALSE(port->CanEnterDPAltMode(&invalid_dpalt_cable));
EXPECT_TRUE(invalid_dpalt_cable);
}
// Check that DPAltMode entry fails with the Belkin TBT3 active cable. That
// cable will not work in DPAltMode, so it should lead to CanEnterDPAltMode
// returning false which will force TBT3 entry in this case.
TEST_F(PortTest, DPAltModeEntryBelkinTBT3ToDock) {
auto port = std::make_unique<Port>(base::FilePath(kFakePort0SysPath), 0);
AddThinkpadTBT3Dock(*port);
AddBelkinTBT3ActiveCable(*port);
EXPECT_FALSE(port->CanEnterDPAltMode(nullptr));
}
// Check that DP Alt Mode Entry works with cable check for a passing case.
// Case: A small Cable Matters dock uses a captive cable. The type-c daemon
// will not recognize a cable for this dock, but because the partner notes it
// uses a captive cable typecd should enter DP Alt Mode without flagging the
// cable as invalid
TEST_F(PortTest, DPAltModeEntryCableMattersDock) {
auto port = std::make_unique<Port>(base::FilePath(kFakePort0SysPath), 0);
AddCableMattersDock(*port);
bool invalid_dpalt_cable = false;
EXPECT_TRUE(port->CanEnterDPAltMode(&invalid_dpalt_cable));
EXPECT_FALSE(invalid_dpalt_cable);
}
// Check that TBT Compat Mode Entry checks work as expected for the following
// working case:
// - Startech.com TB3DK2DPW Alpine Ridge Dock.
// - StarTech Passive Cable 40 Gbps PD 2.0
TEST_F(PortTest, TBTCompatibilityModeEntryCheckTrueStartech) {
auto port = std::make_unique<Port>(base::FilePath(kFakePort0SysPath), 0);
AddStartechTB3DK2DPWDock(*port);
AddStartech40GbpsCable(*port);
EXPECT_EQ(ModeEntryResult::kSuccess, port->CanEnterTBTCompatibilityMode());
}
// Check that TBT Compat Mode Entry checks work as expected for the following
// non-working case:
// - Startech.com TB3DK2DPW Alpine Ridge Dock.
// - Nekteck USB 2.0 cable (5A).
TEST_F(PortTest, TBTCompatibilityModeEntryCheckFalseStartech) {
auto port = std::make_unique<Port>(base::FilePath(kFakePort0SysPath), 0);
AddStartechTB3DK2DPWDock(*port);
AddNekteckUSB2PassiveCable(*port);
EXPECT_EQ(ModeEntryResult::kCableError, port->CanEnterTBTCompatibilityMode());
}
// Check that TBT Compat Mode Entry checks work as expected for the following
// working case:
// - Dell WD19TB dock.
TEST_F(PortTest, TBTCompatibilityModeEntryCheckTrueWD19TB) {
auto port = std::make_unique<Port>(base::FilePath(kFakePort0SysPath), 0);
AddDellWD19TBDock(*port);
EXPECT_EQ(ModeEntryResult::kSuccess, port->CanEnterTBTCompatibilityMode());
}
// Check that USB4 mode checks work as expected for the following
// working case:
// - Intel Gatkex Creek USB4 dock.
// - Belkin TBT3 Passive Cable 40Gbps.
TEST_F(PortTest, USB4EntryTrueGatkexPassiveTBT3Cable) {
auto port = std::make_unique<Port>(base::FilePath(kFakePort0SysPath), 0);
AddIntelUSB4GatkexCreekDock(*port);
AddBelkinTBT3PassiveCable(*port);
EXPECT_EQ(ModeEntryResult::kSuccess, port->CanEnterUSB4());
}
// Check that USB4 mode checks work as expected for the following
// working case:
// - Intel Gatkex Creek USB4 dock.
// - Hongju Full USB 3.1 Gen 1 5A passive cable..
TEST_F(PortTest, USB4EntryTrueGatkexPassiveNonTBT3Cable) {
auto port = std::make_unique<Port>(base::FilePath(kFakePort0SysPath), 0);
AddIntelUSB4GatkexCreekDock(*port);
AddHongjuUSB3p1Gen1Cable(*port);
EXPECT_EQ(ModeEntryResult::kSuccess, port->CanEnterUSB4());
}
// Check that USB4 mode checks work as expected for the following
// non-working case:
// - Intel Gatkex Creek USB4 dock.
// - Nekteck USB 2.0 5A Passive Cable.
TEST_F(PortTest, USB4EntryFalseGatkexPassiveNonTBT3Cable) {
auto port = std::make_unique<Port>(base::FilePath(kFakePort0SysPath), 0);
AddIntelUSB4GatkexCreekDock(*port);
AddNekteckUSB2PassiveCable(*port);
EXPECT_EQ(ModeEntryResult::kCableError, port->CanEnterUSB4());
}
// Check that USB4 mode checks work as expected for the following
// non-working case:
// - Intel Gatkex Creek USB4 dock.
// - Belkin TBT3 Active Cable 40Gbps.
//
// NOTE: This case is interesting because the TBT3 cable fails as it doesn't
// support Rounded Data rates.
TEST_F(PortTest, USB4EntryFalseGatkexActiveTBT3Cable) {
auto port = std::make_unique<Port>(base::FilePath(kFakePort0SysPath), 0);
AddIntelUSB4GatkexCreekDock(*port);
AddBelkinTBT3ActiveCable(*port);
EXPECT_EQ(ModeEntryResult::kCableError, port->CanEnterUSB4());
}
// Check that USB4 mode checks work as expected for the following
// working case:
// - OWC Thunderbolt 4 Dock.
// - Anker USB 3.2 Gen2 cable.
// Additionally check that CableLimitingUSBSpeed() returns true.
TEST_F(PortTest, USB4EntryTrueOWCAnker3p2Gen2Cable) {
auto port = std::make_unique<Port>(base::FilePath(kFakePort0SysPath), 0);
AddOWCTBT4Dock(*port);
AddAnkerUSB3p2Gen2Cable(*port);
EXPECT_EQ(ModeEntryResult::kSuccess, port->CanEnterUSB4());
EXPECT_TRUE(port->CableLimitingUSBSpeed(false));
}
// Check that USB4 mode checks work as expected for the following
// working case:
// - Intel Gatkex Creek USB4 dock.
// - Apple Thunderbolt 3 Pro Cable.
TEST_F(PortTest, USB4EntryTrueGatkexAppleTBT3ProCable) {
auto port = std::make_unique<Port>(base::FilePath(kFakePort0SysPath), 0);
AddIntelUSB4GatkexCreekDock(*port);
AddAppleTBT3ProCable(*port);
EXPECT_EQ(ModeEntryResult::kSuccess, port->CanEnterUSB4());
}
// Check that USB4 mode checks work as expected for the following
// non-working case:
// - Targus DV4K AMA dock.
// - Targus USB 3.2 Gen2 Cable.
//
// This is an interesting case because if AMA VDO is incorrectly interpreted as
// UFP VDO, we may incorrectly consider this dock as USB4 dock while AMA dock
// does not actually support USB4.
TEST_F(PortTest, USB4EntryFalseTargusDV4KTargus3p2Gen2Cable) {
auto port = std::make_unique<Port>(base::FilePath(kFakePort0SysPath), 0);
AddTargusDV4KDock(*port);
AddTargusUSB3p2Gen2Cable(*port);
EXPECT_EQ(ModeEntryResult::kPartnerError, port->CanEnterUSB4());
}
// Check that USB4 mode checks work as expected for the following
// non-working case:
// - Targus 180 AMA dock.
// - Targus USB 3.1 Gen1 Cable.
//
// This is an interesting case because if AMA VDO is incorrectly interpreted as
// UFP VDO, we may incorrectly consider this dock as USB4 dock while AMA dock
// does not actually support USB4.
TEST_F(PortTest, USB4EntryFalseTargus180Targus3p1Gen1Cable) {
auto port = std::make_unique<Port>(base::FilePath(kFakePort0SysPath), 0);
AddTargus180Dock(*port);
AddTargusUSB3p1Gen1Cable(*port);
EXPECT_EQ(ModeEntryResult::kPartnerError, port->CanEnterUSB4());
}
// Check that USB4 device will enter TBT3 mode if the cable does not support
// USB4.
// Case: Thunderbolt 4 OWC dock connected with Belkin active TBT3 cable.
TEST_F(PortTest, USB4ToTBT) {
auto port = std::make_unique<Port>(base::FilePath(kFakePort0SysPath), 0);
AddOWCTBT4Dock(*port);
AddBelkinTBT3ActiveCable(*port);
EXPECT_EQ(ModeEntryResult::kCableError, port->CanEnterUSB4());
EXPECT_EQ(ModeEntryResult::kSuccess, port->CanEnterTBTCompatibilityMode());
}
// Check that USB4 device will enter DPAltMode if the cable does not support
// USB4 or TBT.
// Case: Thunderbolt 4 OWC dock connected with unbranded USB2 cable.
TEST_F(PortTest, USB4ToDPAltMode) {
auto port = std::make_unique<Port>(base::FilePath(kFakePort0SysPath), 0);
AddOWCTBT4Dock(*port);
AddUnbrandedUSB2Cable(*port);
bool invalid_dpalt_cable = false;
EXPECT_EQ(ModeEntryResult::kCableError, port->CanEnterUSB4());
EXPECT_EQ(ModeEntryResult::kCableError, port->CanEnterTBTCompatibilityMode());
// Cable is flagged as invalid, but typecd will still enter DPAltMode. For
// DPAltMode, the cable check is not a condition for mode entry.
EXPECT_TRUE(port->CanEnterDPAltMode(&invalid_dpalt_cable));
EXPECT_TRUE(invalid_dpalt_cable);
}
// Check that CableLimitingUSBSpeed works for "false" case.
// Case: Thunderbolt 4 OWC dock connected with CalDigit Thunderbolt 4 cable.
TEST_F(PortTest, USB4LimitedByCableFalse) {
auto port = std::make_unique<Port>(base::FilePath(kFakePort0SysPath), 0);
AddOWCTBT4Dock(*port);
AddCalDigitTBT4Cable(*port);
EXPECT_EQ(ModeEntryResult::kSuccess, port->CanEnterUSB4());
EXPECT_FALSE(port->CableLimitingUSBSpeed(false));
}
// Check that CableLimitingUSBSpeed works for "true" case.
// Case: Thunderbolt 4 OWC dock connected with Cable Matters USB4 20Gbps cable.
TEST_F(PortTest, USB4LimitedByCableTrue) {
auto port = std::make_unique<Port>(base::FilePath(kFakePort0SysPath), 0);
AddOWCTBT4Dock(*port);
AddCableMatters20GbpsCable(*port);
EXPECT_EQ(ModeEntryResult::kSuccess, port->CanEnterUSB4());
EXPECT_TRUE(port->CableLimitingUSBSpeed(false));
}
// Check that CableLimitingUSBSpeed works for "false" case with passive TBT3
// (USB 3.2 Gen2) Cable.
// Case: Thunderbolt 4 OWC dock connected with unbranded TBT3 cable.
TEST_F(PortTest, USB4LimitedByTBT3PassiveCableFalse) {
auto port = std::make_unique<Port>(base::FilePath(kFakePort0SysPath), 0);
AddOWCTBT4Dock(*port);
AddUnbrandedTBT3Cable(*port);
EXPECT_EQ(ModeEntryResult::kSuccess, port->CanEnterUSB4());
EXPECT_FALSE(port->CableLimitingUSBSpeed(false));
}
// Check that CableLimitingUSBSpeed works for "false" case with passive TBT4
// (USB 3.2 Gen2) LRD Cable.
// Case: Thunderbolt 4 OWC dock connected with Cable Matters TBT4 LRD cable.
TEST_F(PortTest, USB4LimitedByTBT4PassiveLRDCableFalse) {
auto port = std::make_unique<Port>(base::FilePath(kFakePort0SysPath), 0);
AddOWCTBT4Dock(*port);
AddCableMattersTBT4LRDCable(*port);
EXPECT_EQ(ModeEntryResult::kSuccess, port->CanEnterUSB4());
EXPECT_FALSE(port->CableLimitingUSBSpeed(false));
}
// Check that CableLimitingUSBSpeed works for a case with AMA VDO.
// Case: WIMAXIT display connected with Anker USB 3.2 Gen2 cable.
TEST_F(PortTest, BillboardOnlyDisplayNotLimitedByCable) {
auto port = std::make_unique<Port>(base::FilePath(kFakePort0SysPath), 0);
AddWimaxitDisplay(*port);
AddAnkerUSB3p2Gen2Cable(*port);
bool invalid_dpalt_cable = false;
EXPECT_TRUE(port->CanEnterDPAltMode(&invalid_dpalt_cable));
EXPECT_FALSE(invalid_dpalt_cable);
EXPECT_FALSE(port->CableLimitingUSBSpeed(false));
}
// Check that CableLimitingUSBSpeed() returns false for cases using a TBT3
// active cable for USB4.
// Case: Thunderbolt 4 OWC dock with Apple Thunderbolt 3 Pro Cable.
TEST_F(PortTest, CableLimitingSpeedOWCDockAppleTBT3ProCable) {
auto port = std::make_unique<Port>(base::FilePath(kFakePort0SysPath), 0);
AddOWCTBT4Dock(*port);
AddAppleTBT3ProCable(*port);
EXPECT_EQ(ModeEntryResult::kSuccess, port->CanEnterUSB4());
EXPECT_FALSE(port->CableLimitingUSBSpeed(false));
}
// Check that CableLimitingUSBSpeed() returns false after entering TBT3 mode
// with TBT3 dock and passive USB4 Gen3 cable.
// Case: Thinkpad Thunderbolt 3 Dock with Caldigit TBT4 Cable.
TEST_F(PortTest, TBTCableLimitingSpeedTBT3DockFalse) {
auto port = std::make_unique<Port>(base::FilePath(kFakePort0SysPath), 0);
AddThinkpadTBT3Dock(*port);
AddCalDigitTBT4Cable(*port);
EXPECT_EQ(ModeEntryResult::kPartnerError, port->CanEnterUSB4());
EXPECT_EQ(ModeEntryResult::kSuccess, port->CanEnterTBTCompatibilityMode());
EXPECT_FALSE(port->CableLimitingUSBSpeed(true));
}
// Check that CableLimitingUSBSpeed() returns true after entering TBT3 mode
// with TBT3 dock and passive USB 3.2 Gen2 cable.
// Case: Thinkpad Thunderbolt 3 Dock with Anker USB 3.2 Gen2 Cable.
TEST_F(PortTest, TBTCableLimitingSpeedTBT3DockTrue) {
auto port = std::make_unique<Port>(base::FilePath(kFakePort0SysPath), 0);
AddThinkpadTBT3Dock(*port);
AddAnkerUSB3p2Gen2Cable(*port);
EXPECT_EQ(ModeEntryResult::kPartnerError, port->CanEnterUSB4());
EXPECT_EQ(ModeEntryResult::kSuccess, port->CanEnterTBTCompatibilityMode());
EXPECT_TRUE(port->CableLimitingUSBSpeed(true));
}
// Check that CableLimitingUSBSpeed() returns false after entering TBT3 mode
// with TBT3 dock and TBT3 cable.
// Case: Thinkpad Thunderbolt 3 Dock with Belkin TBT3 Passive Cable.
TEST_F(PortTest, TBTCableLimitingSpeedTBT3DockFalseTBT3Cable) {
auto port = std::make_unique<Port>(base::FilePath(kFakePort0SysPath), 0);
AddThinkpadTBT3Dock(*port);
AddBelkinTBT3PassiveCable(*port);
EXPECT_EQ(ModeEntryResult::kPartnerError, port->CanEnterUSB4());
EXPECT_EQ(ModeEntryResult::kSuccess, port->CanEnterTBTCompatibilityMode());
EXPECT_FALSE(port->CableLimitingUSBSpeed(true));
}
// Check the physical location functions GetPanel(), GetHorizontalLocation() and
// GetVerticalLocation() for a valid physical_location.
TEST_F(PortTest, GetPhysicalLocationValid) {
// Set up fake sysfs directory for the ports.
auto port_path = temp_dir_.Append("port0");
ASSERT_TRUE(base::CreateDirectory(port_path));
auto port_physical_location_path = port_path.Append("physical_location");
ASSERT_TRUE(base::CreateDirectory(port_physical_location_path));
auto port_panel_path = port_physical_location_path.Append("panel");
ASSERT_TRUE(
base::WriteFile(port_panel_path, kValidPanel, strlen(kValidPanel)));
auto port_horizontal_position_path =
port_physical_location_path.Append("horizontal_position");
ASSERT_TRUE(base::WriteFile(port_horizontal_position_path,
kValidHorizontalPosition,
strlen(kValidHorizontalPosition)));
auto port_vertical_position_path =
port_physical_location_path.Append("vertical_position");
ASSERT_TRUE(base::WriteFile(port_vertical_position_path,
kValidVerticalPosition,
strlen(kValidVerticalPosition)));
// Create ports.
auto port = std::make_unique<Port>(base::FilePath(port_path), 0);
ASSERT_NE(nullptr, port);
EXPECT_EQ(Panel::kLeft, port->GetPanel());
EXPECT_EQ(HorizontalPosition::kRight, port->GetHorizontalPosition());
EXPECT_EQ(VerticalPosition::kUpper, port->GetVerticalPosition());
}
// Check the physical location functions GetPanel(), GetHorizontalLocation() and
// GetVerticalLocation() for an invalid physical_location.
TEST_F(PortTest, GetPhysicalLocationInvalid) {
// Set up fake sysfs directory for the ports.
auto port_path = temp_dir_.Append("port0");
ASSERT_TRUE(base::CreateDirectory(port_path));
auto port_physical_location_path = port_path.Append("physical_location");
ASSERT_TRUE(base::CreateDirectory(port_physical_location_path));
auto port_panel_path = port_physical_location_path.Append("panel");
ASSERT_TRUE(
base::WriteFile(port_panel_path, kInvalidPanel, strlen(kInvalidPanel)));
auto port_horizontal_position_path =
port_physical_location_path.Append("horizontal_position");
ASSERT_TRUE(base::WriteFile(port_horizontal_position_path,
kInvalidHorizontalPosition,
strlen(kInvalidHorizontalPosition)));
auto port_vertical_position_path =
port_physical_location_path.Append("vertical_position");
ASSERT_TRUE(base::WriteFile(port_vertical_position_path,
kInvalidVerticalPosition,
strlen(kInvalidVerticalPosition)));
// Create ports.
auto port = std::make_unique<Port>(base::FilePath(port_path), 0);
ASSERT_NE(nullptr, port);
EXPECT_EQ(Panel::kUnknown, port->GetPanel());
EXPECT_EQ(HorizontalPosition::kUnknown, port->GetHorizontalPosition());
EXPECT_EQ(VerticalPosition::kUnknown, port->GetVerticalPosition());
}
// Check the physical location functions GetPanel(), GetHorizontalLocation() and
// GetVerticalLocation() when there is no physical_location data available.
TEST_F(PortTest, GetPhysicalLocationNoValue) {
// Set up fake sysfs directory for the ports.
auto port_path = temp_dir_.Append("port0");
ASSERT_TRUE(base::CreateDirectory(port_path));
// Create ports.
auto port = std::make_unique<Port>(base::FilePath(port_path), 0);
ASSERT_NE(nullptr, port);
EXPECT_EQ(Panel::kUnknown, port->GetPanel());
EXPECT_EQ(HorizontalPosition::kUnknown, port->GetHorizontalPosition());
EXPECT_EQ(VerticalPosition::kUnknown, port->GetVerticalPosition());
}
// Check that captive cable is not detected when connected
// cable is not a captive cable.
TEST_F(PortTest, CaptiveCableFalse) {
auto port = std::make_unique<Port>(base::FilePath(kFakePort0SysPath), 0);
AddWimaxitDisplay(*port);
AddAnkerUSB3p2Gen2Cable(*port);
ASSERT_FALSE(port->IsCaptiveCableConnected());
}
// Check that captive cable is detected when connected cable is
// a captive cable.
TEST_F(PortTest, CaptiveCableTrueCableVDO) {
auto port = std::make_unique<Port>(base::FilePath(kFakePort0SysPath), 0);
// DellWD19TB Dock has a cable that reports itself as captive.
// It's not reporting plug type in id header (PD 3.0).
AddDellWD19TBDock(*port);
ASSERT_TRUE(port->IsCaptiveCableConnected());
}
// Check that captive cable is detected when partner device
// reports cable plug in id header VDO.
TEST_F(PortTest, CaptiveCableTrueIdHeaderVDO) {
auto port = std::make_unique<Port>(base::FilePath(kFakePort0SysPath), 0);
base::ScopedTempDir scoped_temp_dir_;
if (!scoped_temp_dir_.CreateUniqueTempDir())
return;
base::FilePath temp_dir_ = scoped_temp_dir_.GetPath();
port->AddPartner(base::FilePath(kFakePort0PartnerSysPath));
// PD ID VDOs wth the plug type set to plug in ID Header.
constexpr uint32_t id_header_vdo =
0xd4008087 |
(kIDHeaderVDOConnectorTypePlug << kIDHeaderVDOConnectorTypeBitOffset);
port->partner_->SetPDRevision(PDRevision::k31);
port->partner_->SetIdHeaderVDO(id_header_vdo);
port->partner_->SetCertStatVDO(0x0);
port->partner_->SetProductVDO(0x0);
port->partner_->SetProductTypeVDO1(0);
port->partner_->SetProductTypeVDO2(0);
port->partner_->SetProductTypeVDO3(0);
ASSERT_TRUE(port->IsCaptiveCableConnected());
}
// Check that captive cable is detected when partner device
// reports cable plug in DP Alt Mode.
TEST_F(PortTest, CaptiveCableTrueDPAltModeVDO) {
auto port = std::make_unique<Port>(base::FilePath(kFakePort0SysPath), 0);
// Cable Matters Dock reports cable plug only in DP Alt mode VDO.
AddCableMattersDock(*port);
ASSERT_TRUE(port->IsCaptiveCableConnected());
}
} // namespace typecd