Skip to content

Commit

Permalink
usdValidation: usdUtils: MissingReferenceValidator
Browse files Browse the repository at this point in the history
created implementation, test, as well as associated entries in plugInfo.json & validatorTokens.h
  • Loading branch information
beersandrew committed Dec 12, 2024
1 parent be52dc6 commit b6e248d
Showing 4 changed files with 96 additions and 10 deletions.
3 changes: 3 additions & 0 deletions pxr/usdValidation/usdUtilsValidators/plugInfo.json
Original file line number Diff line number Diff line change
@@ -3,6 +3,9 @@
{
"Info": {
"Validators": {
"MissingReferenceValidator": {
"doc": "The composed USD stage should not contain any unresolvable asset dependencies (in every possible variation of the asset), when using the default asset resolver."
},
"PackageEncapsulationValidator": {
"doc": "If the root layer is a package, then its recommended for the composed stage to not contain references to files outside the package. The package should be self-contained, warn if not.",
"keywords": [
Original file line number Diff line number Diff line change
@@ -7,6 +7,7 @@

#include "pxr/base/arch/systemInfo.h"
#include "pxr/base/tf/pathUtils.h"
#include "pxr/usd/usdGeom/xform.h"
#include "pxr/usdValidation/usdUtilsValidators/validatorTokens.h"
#include "pxr/usdValidation/usdValidation/error.h"
#include "pxr/usdValidation/usdValidation/registry.h"
@@ -30,7 +31,7 @@ TestUsdUsdzValidators()
UsdValidationValidatorMetadataVector metadata
= registry.GetValidatorMetadataForPlugin(
_tokens->usdUtilsValidatorsPlugin);
TF_AXIOM(metadata.size() == 1);
TF_AXIOM(metadata.size() == 2);
// Since other validators can be registered with a UsdUtilsValidators
// keyword, our validators registered in usd are a subset of the entire
// set.
@@ -40,7 +41,8 @@ TestUsdUsdzValidators()
}

const std::set<TfToken> expectedValidatorNames
= { UsdUtilsValidatorNameTokens->packageEncapsulationValidator };
= { UsdUtilsValidatorNameTokens->packageEncapsulationValidator,
UsdUtilsValidatorNameTokens->missingReferenceValidator };

TF_AXIOM(validatorMetadataNameSet == expectedValidatorNames);
}
@@ -113,11 +115,54 @@ TestPackageEncapsulationValidator()
TF_AXIOM(errors.empty());
}

static void
TestMissingReferenceValidator()
{
UsdValidationRegistry& registry = UsdValidationRegistry::GetInstance();

// Verify the validator exists
const UsdValidationValidator *validator = registry.GetOrLoadValidatorByName(
UsdUtilsValidatorNameTokens->missingReferenceValidator);

TF_AXIOM(validator);

// Create stage with a reference that does not exist
const UsdStageRefPtr& stage = UsdStage::CreateInMemory();

const UsdGeomXform xform = UsdGeomXform::Define(stage, SdfPath("/Xform"));
const SdfReference badReference("doesNotExist.usd");
xform.GetPrim().GetReferences().AddReference(badReference);

UsdValidationErrorVector errors = validator->Validate(stage);

// Verify both the layer & asset errors are present
const TfToken expectedIdentifier =
TfToken(
"usdUtilsValidators:MissingReferenceValidator.UnresolvableDependency");
TF_AXIOM(errors.size() == 1);
TF_AXIOM(errors[0].GetIdentifier() == expectedIdentifier);
TF_AXIOM(errors[0].GetType() == UsdValidationErrorType::Error);
TF_AXIOM(errors[0].GetSites().size() == 1);
TF_AXIOM(!errors[0].GetSites()[0].GetLayer().IsInvalid());
const std::string expectedErrorMessage = "Found unresolvable external "
"dependency 'doesNotExist.usd'.";
TF_AXIOM(errors[0].GetMessage() == expectedErrorMessage);

// Remove the nonexistent reference, add an existing reference
xform.GetPrim().GetReferences().RemoveReference(badReference);
xform.GetPrim().GetReferences().AddReference("pass.usdz");
errors = validator->Validate(stage);

// Verify the errors are gone
TF_AXIOM(errors.empty());
}

int
main()
{
TestUsdUsdzValidators();
TestPackageEncapsulationValidator();
TestMissingReferenceValidator();

return EXIT_SUCCESS;
}
19 changes: 11 additions & 8 deletions pxr/usdValidation/usdUtilsValidators/validatorTokens.h
Original file line number Diff line number Diff line change
@@ -16,18 +16,21 @@

PXR_NAMESPACE_OPEN_SCOPE

#define USD_UTILS_VALIDATOR_NAME_TOKENS \
((packageEncapsulationValidator, \
#define USD_UTILS_VALIDATOR_NAME_TOKENS \
((missingReferenceValidator, \
"usdUtilsValidators:MissingReferenceValidator")) \
((packageEncapsulationValidator, \
"usdUtilsValidators:PackageEncapsulationValidator"))

#define USD_UTILS_VALIDATOR_KEYWORD_TOKENS \
(UsdUtilsValidators) \
#define USD_UTILS_VALIDATOR_KEYWORD_TOKENS \
(UsdUtilsValidators) \
(UsdzValidators)

#define USD_UTILS_VALIDATION_ERROR_NAME_TOKENS \
((layerNotInPackage, "LayerNotInPackage")) \
((assetNotInPackage, "AssetNotInPackage")) \
((invalidLayerInPackage, "InvalidLayerInPackage"))
#define USD_UTILS_VALIDATION_ERROR_NAME_TOKENS \
((layerNotInPackage, "LayerNotInPackage")) \
((assetNotInPackage, "AssetNotInPackage")) \
((invalidLayerInPackage, "InvalidLayerInPackage")) \
((unresolvableDependency, "UnresolvableDependency"))

///\def
/// Tokens representing validator names. Note that for plugin provided
35 changes: 35 additions & 0 deletions pxr/usdValidation/usdUtilsValidators/validators.cpp
Original file line number Diff line number Diff line change
@@ -97,9 +97,44 @@ _PackageEncapsulationValidator(const UsdStagePtr &usdStage)
return errors;
}

static
UsdValidationErrorVector
_MissingReferenceValidator(const UsdStagePtr& usdStage) {
const SdfLayerRefPtr& rootLayer = usdStage->GetRootLayer();

SdfLayerRefPtrVector layers;
std::vector<std::basic_string<char>> assets, unresolvedPaths;
const SdfAssetPath& path = SdfAssetPath(rootLayer->GetIdentifier());

UsdUtilsComputeAllDependencies(path, &layers, &assets, &unresolvedPaths,
nullptr);

UsdValidationErrorVector errors;
for(const std::basic_string<char>& unresolvedPath : unresolvedPaths)
{
errors.emplace_back(
UsdUtilsValidationErrorNameTokens->unresolvableDependency,
UsdValidationErrorType::Error,
UsdValidationErrorSites {
UsdValidationErrorSite(
rootLayer, SdfPath(unresolvedPath))
},
TfStringPrintf(
("Found unresolvable external dependency "
"'%s'."), unresolvedPath.c_str())
);
}

return errors;
}

TF_REGISTRY_FUNCTION(UsdValidationRegistry)
{
UsdValidationRegistry &registry = UsdValidationRegistry::GetInstance();

registry.RegisterPluginValidator(
UsdUtilsValidatorNameTokens->missingReferenceValidator, _MissingReferenceValidator);

registry.RegisterPluginValidator(
UsdUtilsValidatorNameTokens->packageEncapsulationValidator,
_PackageEncapsulationValidator);

0 comments on commit b6e248d

Please sign in to comment.