public async Task TestSymbolResolution()
        {
            CdmCorpusDefinition corpus = TestHelper.GetLocalCorpus(TestsSubpath, "TestSymbolResolution");

            // load the file
            CdmEntityDefinition ent = await corpus.FetchObjectAsync <CdmEntityDefinition>("local:/symbolEntity.cdm.json/symbolEnt");

            ResolveOptions resOpt = new ResolveOptions(ent.InDocument);

            // resolve a reference to the trait object
            CdmObjectBase traitDef = corpus.ResolveSymbolReference(
                resOpt,
                ent.InDocument,
                "symbolEnt/exhibitsTraits/someTraitOnEnt",
                CdmObjectType.TraitDef,
                false
                );

            Assert.IsTrue(traitDef is CdmTraitDefinition);

            // resolve a path to the reference object that contains the trait
            CdmObjectBase traitRef = corpus.ResolveSymbolReference(
                resOpt,
                ent.InDocument,
                "symbolEnt/exhibitsTraits/someTraitOnEnt/(ref)",
                CdmObjectType.TraitDef,
                false
                );

            Assert.IsTrue(traitRef is CdmTraitReference);

            // FetchObjectDefinition on a path to a reference should fetch the actual object
            CdmTraitDefinition traitRefDefinition = traitRef.FetchObjectDefinition <CdmTraitDefinition>(resOpt);
            CdmTraitDefinition traitDefDefinition = traitDef.FetchObjectDefinition <CdmTraitDefinition>(resOpt);

            Assert.AreEqual(traitRefDefinition, traitDef);
            Assert.AreEqual(traitDefDefinition, traitDef);

            CdmObjectBase groupRef = corpus.ResolveSymbolReference(
                resOpt,
                ent.InDocument,
                "symbolEnt/hasAttributes/someGroupRef/(ref)",
                CdmObjectType.AttributeGroupDef,
                false
                );

            Assert.IsTrue(groupRef is CdmAttributeGroupReference);

            CdmObjectBase groupDef = corpus.ResolveSymbolReference(
                resOpt,
                ent.InDocument,
                "symbolEnt/hasAttributes/someGroupRef",
                CdmObjectType.AttributeGroupDef,
                false
                );

            Assert.IsTrue(groupDef is CdmAttributeGroupDefinition);

            // calling FetchObjectDefinition on a symbol to a ref or def should both give the definition
            CdmAttributeGroupDefinition groupRefDefinition = groupRef.FetchObjectDefinition <CdmAttributeGroupDefinition>(resOpt);
            CdmAttributeGroupDefinition groupDefDefinition = groupDef.FetchObjectDefinition <CdmAttributeGroupDefinition>(resOpt);

            Assert.AreEqual(groupRefDefinition, groupDef);
            Assert.AreEqual(groupDefDefinition, groupDef);

            CdmObjectBase typeAtt = corpus.ResolveSymbolReference(
                resOpt,
                ent.InDocument,
                "symbolEnt/hasAttributes/someGroupRef/members/someAttribute",
                CdmObjectType.AttributeGroupDef,
                false
                );

            Assert.IsTrue(typeAtt is CdmTypeAttributeDefinition);
        }
        internal AttributeResolutionContext(ResolveOptions resOpt, CdmAttributeResolutionGuidance resGuide, ResolvedTraitSet traits)
        {
            // collect a set of appliers for all traits
            this.TraitsToApply = traits;
            this.ResGuide      = resGuide;
            this.ResOpt        = resOpt;

            this.ActionsModify       = new List <AttributeResolutionApplier>();
            this.ActionsGroupAdd     = new List <AttributeResolutionApplier>();
            this.ActionsRoundAdd     = new List <AttributeResolutionApplier>();
            this.ActionsAttributeAdd = new List <AttributeResolutionApplier>();
            this.ActionsRemove       = new List <AttributeResolutionApplier>();
            this.ApplierCaps         = null;

            this.ResOpt = CdmObjectBase.CopyResolveOptions(resOpt);

            if (resGuide != null)
            {
                if (this.ApplierCaps == null)
                {
                    this.ApplierCaps = new AttributeResolutionApplierCapabilities()
                    {
                        CanAlterDirectives = false,
                        CanCreateContext   = false,
                        CanRemove          = false,
                        CanAttributeModify = false,
                        CanGroupAdd        = false,
                        CanRoundAdd        = false,
                        CanAttributeAdd    = false
                    }
                }
                ;
                Func <AttributeResolutionApplier, bool> addApplier = (AttributeResolutionApplier apl) =>
                {
                    // Collect the code that will perform the right action.
                    // Associate with the resolved trait and get the priority
                    if (apl.WillAttributeModify != null && apl.DoAttributeModify != null)
                    {
                        this.ActionsModify.Add(apl);
                        this.ApplierCaps.CanAttributeModify = true;
                    }
                    if (apl.WillAttributeAdd != null && apl.DoAttributeAdd != null)
                    {
                        this.ActionsAttributeAdd.Add(apl);
                        this.ApplierCaps.CanAttributeAdd = true;
                    }
                    if (apl.WillGroupAdd != null && apl.DoGroupAdd != null)
                    {
                        this.ActionsGroupAdd.Add(apl);
                        this.ApplierCaps.CanGroupAdd = true;
                    }
                    if (apl.WillRoundAdd != null && apl.DoRoundAdd != null)
                    {
                        this.ActionsRoundAdd.Add(apl);
                        this.ApplierCaps.CanRoundAdd = true;
                    }
                    if (apl.WillAlterDirectives != null && apl.DoAlterDirectives != null)
                    {
                        this.ApplierCaps.CanAlterDirectives = true;
                        apl.DoAlterDirectives(this.ResOpt, resGuide);
                    }
                    if (apl.WillCreateContext != null && apl.DoCreateContext != null)
                    {
                        this.ApplierCaps.CanCreateContext = true;
                    }
                    if (apl.WillRemove != null)
                    {
                        this.ActionsRemove.Add(apl);
                        this.ApplierCaps.CanRemove = true;
                    }
                    return(true);
                };

                if (resGuide.removeAttribute == true)
                {
                    addApplier(PrimitiveAppliers.isRemoved);
                }
                if (resGuide.imposedDirectives != null)
                {
                    addApplier(PrimitiveAppliers.doesImposeDirectives);
                }
                if (resGuide.removedDirectives != null)
                {
                    addApplier(PrimitiveAppliers.doesRemoveDirectives);
                }
                if (resGuide.addSupportingAttribute != null)
                {
                    addApplier(PrimitiveAppliers.doesAddSupportingAttribute);
                }
                if (resGuide.renameFormat != null)
                {
                    addApplier(PrimitiveAppliers.doesDisambiguateNames);
                }
                if (resGuide.cardinality == "many")
                {
                    addApplier(PrimitiveAppliers.doesExplainArray);
                }
                if (resGuide.entityByReference != null)
                {
                    addApplier(PrimitiveAppliers.doesReferenceEntityVia);
                }

                if (resGuide.selectsSubAttribute != null && resGuide.selectsSubAttribute.selects == "one")
                {
                    addApplier(PrimitiveAppliers.doesSelectAttributes);
                }

                // sorted by priority
                this.ActionsModify.Sort((l, r) => l.Priority - r.Priority);
                this.ActionsGroupAdd.Sort((l, r) => l.Priority - r.Priority);
                this.ActionsRoundAdd.Sort((l, r) => l.Priority - r.Priority);
                this.ActionsAttributeAdd.Sort((l, r) => l.Priority - r.Priority);
            }
        }
    }