Increase unit test code coverage of `controller/` by 2.3% (#39941)

* Add unit tests for `BtpEngine` sequence number handling

- Test that the initial value of the last received sequence number is zero.
- Test that the initial value of the newest unacknowledged sent sequence number is zero.
- Test that sending a packet updates the unacknowledged sequence number correctly and that receiving an acknowledgment updates the state as expected.

* Restyle

* Check newest unacked sent sequence number

* Combine test cases for initial sequence numbers

* Restyle

* Add a friend accessor class

* Add an accessor class

* Add unit Test for

* Fix typos; Improve comments

* Fix typos; Restyle

* Restyle

* Remove s

* Add  as  source file

* Remove redundant `chip::`s

* Restyle

* Update AutoCommissionerTestAccess.h

* Add comments
diff --git a/src/controller/AutoCommissioner.h b/src/controller/AutoCommissioner.h
index 038be19..7f95123 100644
--- a/src/controller/AutoCommissioner.h
+++ b/src/controller/AutoCommissioner.h
@@ -26,12 +26,22 @@
 #include <protocols/secure_channel/RendezvousParameters.h>
 
 namespace chip {
+
+namespace Test {
+
+class AutoCommissionerTestAccess;
+
+} // namespace Test
+
 namespace Controller {
 
 class DeviceCommissioner;
 
 class AutoCommissioner : public CommissioningDelegate
 {
+
+    friend class chip::Test::AutoCommissionerTestAccess;
+
 public:
     AutoCommissioner();
     ~AutoCommissioner() override;
@@ -137,6 +147,7 @@
     app::Clusters::TimeSynchronization::Structs::DSTOffsetStruct::Type mDstOffsetsBuf[kMaxSupportedDstStructs];
 
     static constexpr size_t kMaxDefaultNtpSize = 128;
+
     char mDefaultNtp[kMaxDefaultNtpSize];
 
     uint8_t mICDSymmetricKey[Crypto::kAES_CCM128_Key_Length];
diff --git a/src/controller/tests/AutoCommissionerTestAccess.h b/src/controller/tests/AutoCommissionerTestAccess.h
new file mode 100644
index 0000000..193324f
--- /dev/null
+++ b/src/controller/tests/AutoCommissionerTestAccess.h
@@ -0,0 +1,56 @@
+/*
+ *
+ *    Copyright (c) 2020-2025 Project CHIP Authors
+ *    All rights reserved.
+ *
+ *    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.
+ */
+#pragma once
+
+#include <controller/AutoCommissioner.h>
+
+#include <lib/core/StringBuilderAdapters.h>
+#include <lib/support/CHIPMemString.h>
+
+#include <app/AttributePathParams.h>
+#include <controller/CommissioneeDeviceProxy.h>
+#include <controller/CommissioningDelegate.h>
+#include <credentials/DeviceAttestationConstructor.h>
+#include <crypto/CHIPCryptoPAL.h>
+#include <lib/support/ScopedBuffer.h>
+#include <protocols/secure_channel/RendezvousParameters.h>
+
+namespace chip {
+
+namespace Test {
+// Provides access to private/protected members of AutoCommissioner class for testing
+class AutoCommissionerTestAccess
+{
+public:
+    AutoCommissionerTestAccess() = delete;
+    AutoCommissionerTestAccess(Controller::AutoCommissioner * commissioner) : mCommissioner(commissioner) {}
+
+    Controller::CommissioningStage AccessGetNextCommissioningStageInternal(Controller::CommissioningStage currentStage,
+                                                                           CHIP_ERROR & lastErr)
+    {
+        return mCommissioner->GetNextCommissioningStageInternal(currentStage, lastErr);
+    }
+    void SetBreadcrumb(uint64_t value) { mCommissioner->mDeviceCommissioningInfo.general.breadcrumb = value; }
+    void SetUTCRequirements(bool requiresUTC) { mCommissioner->mDeviceCommissioningInfo.requiresUTC = requiresUTC; }
+
+private:
+    Controller::AutoCommissioner * mCommissioner = nullptr;
+};
+
+} // namespace Test
+} // namespace chip
diff --git a/src/controller/tests/BUILD.gn b/src/controller/tests/BUILD.gn
index 2c1f6dc..00a7203 100644
--- a/src/controller/tests/BUILD.gn
+++ b/src/controller/tests/BUILD.gn
@@ -62,6 +62,8 @@
 
   cflags = [ "-Wconversion" ]
 
+  sources = [ "AutoCommissionerTestAccess.h" ]
+
   public_deps = [
     "${chip_root}/src/app/common:cluster-objects",
     "${chip_root}/src/app/tests:helpers",
diff --git a/src/controller/tests/TestAutoCommissioner.cpp b/src/controller/tests/TestAutoCommissioner.cpp
index ab65e7d..dbc0fca 100644
--- a/src/controller/tests/TestAutoCommissioner.cpp
+++ b/src/controller/tests/TestAutoCommissioner.cpp
@@ -19,7 +19,8 @@
 #include <pw_unit_test/framework.h>
 
 #include <controller/AutoCommissioner.h>
-
+#include <controller/CommissioningDelegate.h>
+#include <controller/tests/AutoCommissionerTestAccess.h>
 #include <lib/core/StringBuilderAdapters.h>
 #include <lib/support/CHIPMemString.h>
 
@@ -29,6 +30,7 @@
 using namespace chip;
 using namespace chip::Dnssd;
 using namespace chip::Controller;
+using namespace chip::Test;
 
 namespace {
 
@@ -219,4 +221,122 @@
     ASSERT_EQ(pathParams[0].mAttributeId, attributeId);
 }
 
+// kStages are enumerators from enum type name CommissioningStage
+struct StageTransition
+{
+    CommissioningStage currentStage;
+    CommissioningStage nextStage;
+};
+
+const std::vector<StageTransition> kStagePairs = {
+    // Only linear transitions are tested here;
+    // Branching cases (like kReadCommissioningInfo, kConfigureTCAcknowledgments, etc.) are tested separately
+    { kSecurePairing, kReadCommissioningInfo },
+    { kArmFailsafe, kConfigRegulatory },
+    { kConfigRegulatory, kConfigureTCAcknowledgments },
+    { kConfigureDefaultNTP, kSendPAICertificateRequest },
+    { kSendPAICertificateRequest, kSendDACCertificateRequest },
+    { kSendDACCertificateRequest, kSendAttestationRequest },
+    { kSendAttestationRequest, kAttestationVerification },
+    { kAttestationVerification, kAttestationRevocationCheck },
+    { kJFValidateNOC, kSendVIDVerificationRequest },
+    { kSendVIDVerificationRequest, kSendOpCertSigningRequest },
+    { kSendOpCertSigningRequest, kValidateCSR },
+    { kValidateCSR, kGenerateNOCChain },
+    { kGenerateNOCChain, kSendTrustedRootCert },
+    { kSendTrustedRootCert, kSendNOC },
+    { kICDGetRegistrationInfo, kICDRegistration },
+    { kScanNetworks, kNeedsNetworkCreds },
+    { kWiFiNetworkSetup, kFailsafeBeforeWiFiEnable },
+    { kThreadNetworkSetup, kFailsafeBeforeThreadEnable },
+    { kFailsafeBeforeWiFiEnable, kWiFiNetworkEnable },
+    { kFailsafeBeforeThreadEnable, kThreadNetworkEnable },
+    { kEvictPreviousCaseSessions, kFindOperationalForStayActive },
+    { kFindOperationalForStayActive, kICDSendStayActive },
+    { kICDSendStayActive, kFindOperationalForCommissioningComplete },
+    { kFindOperationalForCommissioningComplete, kSendComplete },
+    { kSendComplete, kCleanup },
+    { kCleanup, kError },
+    { kError, kError },
+    { static_cast<CommissioningStage>(250), kError }, // triggers default case in switch statement
+
+};
+
+// Test each case pair for the next commissioning stage
+TEST_F(AutoCommissionerTest, NextCommissioningStage)
+{
+    // Accessor class used due to private/protected members.
+    AutoCommissionerTestAccess privateConfigCommissioner(&mCommissioner);
+    CHIP_ERROR err = CHIP_NO_ERROR;
+
+    for (const auto & stagePair : kStagePairs)
+    {
+        CommissioningStage nextStage =
+            privateConfigCommissioner.AccessGetNextCommissioningStageInternal(stagePair.currentStage, err);
+        EXPECT_EQ(nextStage, stagePair.nextStage);
+    }
+}
+
+// if commissioning is manually stopped, the next stage should be kCleanup
+TEST_F(AutoCommissionerTest, NextStageStopCommissioning)
+{
+    AutoCommissionerTestAccess privateConfigCommissioner(&mCommissioner);
+    mCommissioner.StopCommissioning();
+
+    CHIP_ERROR err           = CHIP_ERROR_INTERNAL;
+    CommissioningStage stage = privateConfigCommissioner.AccessGetNextCommissioningStageInternal(kSecurePairing, err);
+    EXPECT_EQ(stage, kCleanup);
+}
+
+// if commissioning failed, then the next stage should be cleanup
+TEST_F(AutoCommissionerTest, NextCommissioningStageAfterError)
+{
+    AutoCommissionerTestAccess privateConfigCommissioner(&mCommissioner);
+
+    CHIP_ERROR err           = CHIP_ERROR_INTERNAL;
+    CommissioningStage stage = privateConfigCommissioner.AccessGetNextCommissioningStageInternal(kSecurePairing, err);
+    EXPECT_EQ(stage, kCleanup);
+}
+
+// Verifies that the commissioner proceeds to ConfigureTCAcknowledgments under the correct conditions.
+TEST_F(AutoCommissionerTest, NextStageReadCommissioningInfo)
+{
+    AutoCommissionerTestAccess privateConfigCommissioner(&mCommissioner);
+    CHIP_ERROR err = CHIP_NO_ERROR;
+
+    privateConfigCommissioner.SetBreadcrumb(0);
+    CommissioningStage nextStage = privateConfigCommissioner.AccessGetNextCommissioningStageInternal(kReadCommissioningInfo, err);
+
+    EXPECT_EQ(nextStage, kArmFailsafe);
+
+    // if breadcrumb > 0, the stage changes to kSendNOC; subsequent stages progress accordingly.
+    privateConfigCommissioner.SetBreadcrumb(1);
+
+    CommissioningStage nextStageReadCommissioningInfo =
+        privateConfigCommissioner.AccessGetNextCommissioningStageInternal(kReadCommissioningInfo, err);
+    CommissioningStage nextStageSendNOC = privateConfigCommissioner.AccessGetNextCommissioningStageInternal(kSendNOC, err);
+
+    EXPECT_EQ(nextStageReadCommissioningInfo, nextStageSendNOC);
+}
+
+// Ensures TCAcknowledgment stage is triggered only under expected commissioning conditions.
+TEST_F(AutoCommissionerTest, NextStageConfigureTCAcknowledgments)
+{
+    AutoCommissionerTestAccess privateConfigCommissioner(&mCommissioner);
+    CHIP_ERROR err = CHIP_NO_ERROR;
+
+    privateConfigCommissioner.SetUTCRequirements(true);
+
+    CommissioningStage nextStage =
+        privateConfigCommissioner.AccessGetNextCommissioningStageInternal(kConfigureTCAcknowledgments, err);
+
+    EXPECT_EQ(nextStage, kConfigureUTCTime);
+
+    privateConfigCommissioner.SetUTCRequirements(false);
+
+    nextStage = privateConfigCommissioner.AccessGetNextCommissioningStageInternal(kConfigureTCAcknowledgments, err);
+
+    EXPECT_EQ(nextStage, kSendPAICertificateRequest);
+}
+
 } // namespace