Skip to content

Commit

Permalink
Added a scoped value changer, mainly for unit test usage (#31513)
Browse files Browse the repository at this point in the history
* Added a scoped value changer, mainly for unit test usage

* Restyle

* Fix shadow variable naming

* Fix name collision due to copy and paste

* Update based on code review

* Restyle

---------

Co-authored-by: Andrei Litvin <andreilitvin@google.com>
  • Loading branch information
2 people authored and pull[bot] committed Apr 8, 2024
1 parent a6d07c7 commit 1002952
Show file tree
Hide file tree
Showing 4 changed files with 185 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/lib/support/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ static_library("support") {
"PrivateHeap.cpp",
"PrivateHeap.h",
"ReferenceCountedHandle.h",
"Scoped.h",
"SerializableIntegerSet.cpp",
"SerializableIntegerSet.h",
"SetupDiscriminator.h",
Expand Down
81 changes: 81 additions & 0 deletions src/lib/support/Scoped.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
*
* Copyright (c) 2024 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

namespace chip {

template <typename T>
class ScopedChange;

/// Allows a value to only be changed within a scope.
///
/// Generally used to force determinism for unit test execution.
///
/// When a variable of this type is used, it should
/// only be changed via `ScopedChange`.
template <typename T>
class ScopedChangeOnly
{
public:
explicit ScopedChangeOnly(T initial) : mValue(initial) {}
operator T() const { return mValue; }

private:
T mValue;

// Expected to be used only by ScopedChange<T> only
T & InternalMutableValue() { return mValue; }
friend class ScopedChange<T>;
};

/// Allows a scoped mutation to occur on a variable.
///
/// When an instance of this class goes out of scope, the variable
/// will be reset to the default.
///
/// Example usage
///
/// int a = 123;
/// ScopedChangeOnly b(234);
///
/// /* a == 123, b == 234 */
/// {
/// ScopedChange changeA(a, 321);
/// /* a == 321, b == 234 */
/// {
/// ScopedChange changeB(b, 10);
/// /* a == 321, b == 10 */
/// }
/// /* a == 321, b == 234 */
/// }
/// /* a == 123, b == 234 */
///
template <typename T>
class ScopedChange
{
public:
ScopedChange(ScopedChangeOnly<T> & what, T value) : mValue(what.InternalMutableValue()), mOriginal(what) { mValue = value; }
ScopedChange(T & what, T value) : mValue(what), mOriginal(what) { mValue = value; }
~ScopedChange() { mValue = mOriginal; }

private:
T & mValue;
T mOriginal;
};

} // namespace chip
1 change: 1 addition & 0 deletions src/lib/support/tests/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ chip_test_suite_using_nltest("tests") {
"TestPrivateHeap.cpp",
"TestSafeInt.cpp",
"TestSafeString.cpp",
"TestScoped.cpp",
"TestScopedBuffer.cpp",
"TestSerializableIntegerSet.cpp",
"TestSpan.cpp",
Expand Down
102 changes: 102 additions & 0 deletions src/lib/support/tests/TestScoped.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/*
*
* Copyright (c) 2024 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.
*/

#include <lib/support/Scoped.h>
#include <lib/support/UnitTestRegistration.h>

#include <nlunit-test.h>
#include <string.h>

namespace {

using namespace chip;

void TestScopedVariableChange(nlTestSuite * inSuite, void * inContext)
{
int x = 123;

{
ScopedChange change1(x, 10);
NL_TEST_ASSERT(inSuite, x == 10);

x = 15;
{
ScopedChange change2(x, 20);
NL_TEST_ASSERT(inSuite, x == 20);
}
NL_TEST_ASSERT(inSuite, x == 15);
}
NL_TEST_ASSERT(inSuite, x == 123);
}

void TestScopedChangeOnly(nlTestSuite * inSuite, void * inContext)
{
ScopedChangeOnly intValue(123);
ScopedChangeOnly strValue("abc");

NL_TEST_ASSERT(inSuite, intValue == 123);
NL_TEST_ASSERT(inSuite, strcmp(strValue, "abc") == 0);

{
ScopedChange change1(intValue, 234);

NL_TEST_ASSERT(inSuite, intValue == 234);
NL_TEST_ASSERT(inSuite, strcmp(strValue, "abc") == 0);

ScopedChange change2(strValue, "xyz");
NL_TEST_ASSERT(inSuite, intValue == 234);
NL_TEST_ASSERT(inSuite, strcmp(strValue, "xyz") == 0);

{
ScopedChange change3(intValue, 10);
ScopedChange change4(strValue, "test");

NL_TEST_ASSERT(inSuite, intValue == 10);
NL_TEST_ASSERT(inSuite, strcmp(strValue, "test") == 0);
}

NL_TEST_ASSERT(inSuite, intValue == 234);
NL_TEST_ASSERT(inSuite, strcmp(strValue, "xyz") == 0);
}

NL_TEST_ASSERT(inSuite, intValue == 123);
NL_TEST_ASSERT(inSuite, strcmp(strValue, "abc") == 0);
}

} // namespace

#define NL_TEST_DEF_FN(fn) NL_TEST_DEF("Test " #fn, fn)
/**
* Test Suite. It lists all the test functions.
*/
static const nlTest sTests[] = {
NL_TEST_DEF_FN(TestScopedVariableChange), //
NL_TEST_DEF_FN(TestScopedChangeOnly), //
NL_TEST_SENTINEL() //
};

int TestScoped()
{
nlTestSuite theSuite = { "CHIP Scoped tests", &sTests[0], nullptr, nullptr };

// Run test suite against one context.
nlTestRunner(&theSuite, nullptr);
return nlTestRunnerStats(&theSuite);
}

CHIP_REGISTER_TEST_SUITE(TestScoped)

0 comments on commit 1002952

Please sign in to comment.