Skip to content

Commit

Permalink
Add Darwin chip tool tests (#15823)
Browse files Browse the repository at this point in the history
* Convert XCTest code gen to YAML tests.

* Generated code.
  • Loading branch information
Josh V [Apple] authored Mar 8, 2022
1 parent d8c337f commit bade418
Show file tree
Hide file tree
Showing 20 changed files with 76,358 additions and 15 deletions.
1 change: 1 addition & 0 deletions examples/chip-tool-darwin/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ assert(chip_build_tools)

executable("chip-tool-darwin") {
sources = [
"${chip_root}/zzz_generated/chip-tool-darwin/zap-generated/cluster/CHIPTestClustersObjc.mm",
"commands/clusters/ModelCommandBridge.mm",
"commands/common/CHIPCommandBridge.mm",
"commands/common/CHIPCommandStorageDelegate.mm",
Expand Down
262 changes: 262 additions & 0 deletions examples/chip-tool-darwin/commands/tests/TestCommandBridge.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,262 @@
/*
* Copyright (c) 2022 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 "../common/CHIPCommandBridge.h"
#include <app/tests/suites/include/ConstraintsChecker.h>
#include <app/tests/suites/include/PICSChecker.h>
#include <app/tests/suites/include/ValueChecker.h>
#include <lib/support/UnitTestUtils.h>
#include <zap-generated/cluster/CHIPTestClustersObjc.h>

#import <CHIP/CHIPError.h>

constexpr uint16_t kTimeoutInSeconds = 90;

class TestCommandBridge : public CHIPCommandBridge, public ValueChecker, public ConstraintsChecker, public PICSChecker {
public:
TestCommandBridge(const char * _Nonnull commandName)
: CHIPCommandBridge(commandName)
{
AddArgument("node-id", 0, UINT64_MAX, &mNodeId);
AddArgument("delayInMs", 0, UINT64_MAX, &mDelayInMs);
AddArgument("PICS", &mPICSFilePath);
}

~TestCommandBridge() {};

/////////// CHIPCommand Interface /////////
CHIP_ERROR RunCommand() override
{
if (mPICSFilePath.HasValue()) {
PICS.SetValue(PICSBooleanReader::Read(mPICSFilePath.Value()));
}

mCallbackQueue = dispatch_queue_create("com.chip-tool.command", DISPATCH_QUEUE_SERIAL);

NextTest();
return CHIP_NO_ERROR;
}

chip::System::Clock::Timeout GetWaitDuration() const override { return chip::System::Clock::Seconds16(kTimeoutInSeconds); }

virtual void NextTest() = 0;

void Exit(std::string message) override
{
ChipLogError(chipTool, " ***** Test Failure: %s\n", message.c_str());
SetCommandExitStatus(CHIP_ERROR_INTERNAL);
}

/////////// GlobalCommands Interface /////////
void Log(NSString * _Nonnull message)
{
NSLog(@"%@", message);
NextTest();
}

void WaitForMs(unsigned int ms)
{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, ms * NSEC_PER_MSEC), mCallbackQueue, ^{
NextTest();
});
}

void UserPrompt(NSString * _Nonnull message) { NextTest(); }

void WaitForCommissionee(chip::NodeId nodeId)
{
CHIPDeviceController * controller = [CHIPDeviceController sharedController];
VerifyOrReturn(controller != nil, SetCommandExitStatus(CHIP_ERROR_INCORRECT_STATE));

[controller getConnectedDevice:nodeId
queue:mCallbackQueue
completionHandler:^(CHIPDevice * _Nullable device, NSError * _Nullable error) {
CHIP_ERROR err = [CHIPError errorToCHIPErrorCode:error];
VerifyOrReturn(CHIP_NO_ERROR == err, SetCommandExitStatus(err));

mConnectedDevice = device;
NextTest();
}];
}

CHIPDevice * _Nullable GetConnectedDevice(void) { return mConnectedDevice; }

protected:
dispatch_queue_t _Nullable mCallbackQueue;
CHIPDevice * _Nullable mConnectedDevice;
chip::NodeId mNodeId;

void Wait()
{
if (mDelayInMs.HasValue()) {
chip::test_utils::SleepMillis(mDelayInMs.Value());
}
};

chip::Optional<uint64_t> mDelayInMs;
chip::Optional<char *> mPICSFilePath;
chip::Optional<chip::EndpointId> mEndpointId;
chip::Optional<uint16_t> mTimeout;

bool CheckConstraintStartsWith(
const char * _Nonnull itemName, const NSString * _Nonnull current, const char * _Nonnull expected)
{
const chip::CharSpan value([current UTF8String], [current lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
return ConstraintsChecker::CheckConstraintStartsWith(itemName, value, expected);
}

bool CheckConstraintEndsWith(const char * _Nonnull itemName, const NSString * _Nonnull current, const char * _Nonnull expected)
{
const chip::CharSpan value([current UTF8String], [current lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
return ConstraintsChecker::CheckConstraintEndsWith(itemName, value, expected);
}

bool CheckConstraintIsUpperCase(const char * _Nonnull itemName, const NSString * _Nonnull current, bool expectUpperCase)
{
const chip::CharSpan value([current UTF8String], [current lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
return ConstraintsChecker::CheckConstraintIsUpperCase(itemName, value, expectUpperCase);
}

bool CheckConstraintIsLowerCase(const char * _Nonnull itemName, const NSString * _Nonnull current, bool expectLowerCase)
{
const chip::CharSpan value([current UTF8String], [current lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
return ConstraintsChecker::CheckConstraintIsLowerCase(itemName, value, expectLowerCase);
}

bool CheckConstraintIsHexString(const char * _Nonnull itemName, const NSString * _Nonnull current, bool expectHexString)
{
const chip::CharSpan value([current UTF8String], [current lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
return ConstraintsChecker::CheckConstraintIsHexString(itemName, value, expectHexString);
}

bool CheckConstraintNotValue(
const char * _Nonnull itemName, const NSString * _Nonnull current, const NSString * _Nonnull expected)
{
const chip::CharSpan currentValue([current UTF8String], [current lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
const chip::CharSpan expectedValue([expected UTF8String], [expected lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
return ConstraintsChecker::CheckConstraintNotValue(itemName, currentValue, expectedValue);
}

bool CheckConstraintNotValue(const char * _Nonnull itemName, const NSData * _Nonnull current, const NSData * _Nonnull expected)
{
const chip::ByteSpan currentValue(static_cast<const uint8_t *>([current bytes]), [current length]);
const chip::ByteSpan expectedValue(static_cast<const uint8_t *>([expected bytes]), [expected length]);
return ConstraintsChecker::CheckConstraintNotValue(itemName, currentValue, expectedValue);
}

bool CheckConstraintNotValue(const char * _Nonnull itemName, const NSNumber * _Nonnull current, NSNumber * _Nonnull expected)
{
if ([current isEqualToNumber:expected]) {
Exit(std::string(itemName) + " got unexpected value: " + std::string([[current stringValue] UTF8String]));
return false;
}

return true;
}

template <typename T>
bool CheckConstraintNotValue(const char * _Nonnull itemName, const NSNumber * _Nonnull current, T expected)
{
return CheckConstraintNotValue(itemName, current, @(expected));
}

template <typename T> bool CheckConstraintNotValue(const char * _Nonnull itemName, NSError * _Nullable current, T expected)
{
NSNumber * currentValue = @([CHIPError errorToCHIPErrorCode:current].AsInteger());
return CheckConstraintNotValue(itemName, currentValue, @(expected));
}

bool CheckValueAsString(const char * _Nonnull itemName, const id _Nonnull current, const NSString * _Nonnull expected)
{
NSString * data = current;
const chip::CharSpan currentValue([data UTF8String], [data lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
const chip::CharSpan expectedValue([expected UTF8String], [expected lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
return ValueChecker::CheckValueAsString(itemName, currentValue, expectedValue);
}

bool CheckValueAsString(const char * _Nonnull itemName, const id _Nonnull current, const NSData * _Nonnull expected)
{
NSData * data = current;
const chip::ByteSpan currentValue(static_cast<const uint8_t *>([data bytes]), [data length]);
const chip::ByteSpan expectedValue(static_cast<const uint8_t *>([expected bytes]), [expected length]);
return ValueChecker::CheckValueAsString(itemName, currentValue, expectedValue);
}

bool CheckValue(const char * _Nonnull itemName, NSNumber * _Nonnull current, NSNumber * _Nonnull expected)
{
if (![current isEqualToNumber:expected]) {
Exit(std::string(itemName) + " value mismatch: expected " + std::string([[expected stringValue] UTF8String])
+ " but got " + std::string([[current stringValue] UTF8String]));
return false;
}

return true;
}

bool CheckValue(const char * _Nonnull itemName, id _Nonnull current, NSNumber * _Nonnull expected)
{
NSNumber * currentValue = current;
return CheckValue(itemName, currentValue, expected);
}

template <typename T> bool CheckValue(const char * _Nonnull itemName, NSNumber * _Nonnull current, T expected)
{
return CheckValue(itemName, current, @(expected));
}

template <typename T> bool CheckValue(const char * _Nonnull itemName, id _Nonnull current, T expected)
{
NSNumber * currentValue = current;
return CheckValue(itemName, currentValue, @(expected));
}

template <typename T> bool CheckValue(const char * _Nonnull itemName, NSError * _Nullable current, T expected)
{

NSNumber * currentValue = @([CHIPError errorToCHIPErrorCode:current].AsInteger());
return CheckValue(itemName, currentValue, @(expected));
}

template <typename T, typename U> bool CheckValue(const char * _Nonnull itemName, T current, U expected)
{

return ValueChecker::CheckValue(itemName, current, expected);
}

bool CheckValueNonNull(const char * _Nonnull itemName, id _Nullable current)
{
if (current != nil) {
return true;
}

Exit(std::string(itemName) + " expected to not be null but is");
return false;
}

bool CheckValueNull(const char * _Nonnull itemName, id _Nullable current)
{
if (current == nil) {
return true;
}

Exit(std::string(itemName) + " expected to be null but isn't");
return false;
}
};
3 changes: 3 additions & 0 deletions examples/chip-tool-darwin/main.mm
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,15 @@
#include "commands/common/Commands.h"

#include "commands/pairing/Commands.h"

#include <zap-generated/cluster/Commands.h>
#include <zap-generated/test/Commands.h>

int main(int argc, const char * argv[])
{
Commands commands;
registerCommandsPairing(commands);
registerCommandsTests(commands);
registerClusters(commands);
return commands.Run(argc, (char **) argv);
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
{{#if (chip_has_client_clusters)}}
{{> header}}
#import <Foundation/Foundation.h>
#import <CHIP/CHIPError_Internal.h>

#import "CHIPCallbackBridge_internal.h"
#import "CHIP/zap-generated/CHIPCallbackBridge_internal.h"
#import "CHIPCluster_internal.h"
#import "CHIPDevice.h"
#import "CHIPDevice_Internal.h"
Expand Down
61 changes: 61 additions & 0 deletions examples/chip-tool-darwin/templates/helper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
*
* Copyright (c) 2021 Project CHIP Authors
*
* 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.
*/

// Import helpers from zap core
const zapPath = '../../../third_party/zap/repo/dist/src-electron/';
const { asB_locks, ensureClusters } = require('../../../src/app/zap-templates/common/ClustersHelper.js');
const templateUtil = require(zapPath + 'generator/template-util.js');
const zclHelper = require(zapPath + 'generator/helper-zcl.js');
const zclQuery = require(zapPath + 'db/query-zcl.js');

const ChipTypesHelper = require('../../../src/app/zap-templates/common/ChipTypesHelper.js');

function asHyphenatedLower(name)
{
name = name.replace(/\s+/g, '').replace(/\.?([A-Z])/g, function(x) {
return '-' + x
})
return name.substring(1).toLowerCase();
}

function toLowerCase(name)
{
return name.toLowerCase();
}

function getCommands()
{
return ensureClusters(this).getClientCommands(this.name);
}

function hasCommands()
{
return getCommands.call(this).then(commands => { return !!commands.length });
}

function hasArguments()
{
return !!this.arguments.length
}

//
// Module exports
//
exports.asHyphenatedLower = asHyphenatedLower;
exports.hasCommands = hasCommands;
exports.toLowerCase = toLowerCase
exports.hasArguments = hasArguments;
Loading

0 comments on commit bade418

Please sign in to comment.