Esempio n. 1
0
        public override UPnPTestStates Run(ICollection otherSubTests, CdsSubTestArgument arg)
        {
            this._TestState = UPnPTestStates.Running;

            CpContentDirectory CDS = this.GetCDS(arg._Device);

            _Details = new CdsResult_GetSystemUpdateID();

            uint updateID = 0;

            try
            {
                if (CDS != null)
                {
                    DateTime start = System.DateTime.Now;
                    CDS.Sync_GetSystemUpdateID(out updateID);
                    this.LogResponseTime(start, _Details, arg);
                }
            }
            catch (UPnPInvokeException ie)
            {
                arg.TestGroup.AddResult(this._Name + " test failed because of an invocation error: " + ie.Message);
                return(UPnPTestStates.Failed);
            }

            arg._TestGroupState.SystemUpdateID = updateID;

            arg.TestGroup.AddResult(this._Name + " test passed. Returned=\"" + updateID.ToString() + "\".");
            this._TestState = UPnPTestStates.Pass;
            return(this._TestState);
        }
        protected void LogResponseTime(DateTime started, CdsTestResult result, CdsSubTestArgument arg)
        {
            DateTime end = DateTime.Now;

            long ticks = end.Ticks - started.Ticks;
            long millisec = ticks / 10000;

            result.ResponseTime = millisec;
            arg._TestGroup.AddEvent(LogImportance.Remark, this._Name, this._Name + " subtest completion time: " + millisec.ToString() + "ms.");
        }
Esempio n. 3
0
        protected void LogResponseTime(DateTime started, CdsTestResult result, CdsSubTestArgument arg)
        {
            DateTime end = DateTime.Now;

            long ticks    = end.Ticks - started.Ticks;
            long millisec = ticks / 10000;

            result.ResponseTime = millisec;
            arg._TestGroup.AddEvent(LogImportance.Remark, this._Name, this._Name + " subtest completion time: " + millisec.ToString() + "ms.");
        }
        public override void Start(UPnPDevice device)
        {
            UPnPDevice d = device;
            UPnPService[] services = d.GetServices(CpContentDirectory.SERVICE_NAME);
            if (services == null || services.Length == 0)
            {
                enabled = false;
                return;
            }

            CdsSubTestArgument arg = new CdsSubTestArgument();
            arg._Device = device;
            arg._TestGroupState = new CdsTestGroupState();
            arg._TestGroup = this;
            this.RunTests(null, arg);
        }
Esempio n. 5
0
        /// <summary>
        /// Updates the <see cref="CdsSubTestArgument.SystemUpdateID"/> value with the specified ID.
        /// Checks the current value of the state variable and returns zero if the
        /// specified ID matches the value of the state variable.
        /// </summary>
        /// <param name="updateID"></param>
        /// <param name="arg"></param>
        /// <returns>0=equal; 1=updateID is greater than device's state variable; -1=updateID is less than device's state variable</returns>
        public static int UpdateSystemUpdateID(uint updateID, CdsSubTestArgument arg, CdsSubTest sub)
        {
            arg._TestGroupState.SystemUpdateID = updateID;

            CpContentDirectory CDS = sub.GetCDS(arg._Device);

            uint updateID2 = CDS.SystemUpdateID;

            if (updateID > updateID2)
            {
                return(1);
            }
            else if (updateID < updateID2)
            {
                return(-1);
            }

            return(0);
        }
        public override void Start(UPnPDevice device)
        {
            UPnPDevice d = device;

            UPnPService[] services = d.GetServices(CpContentDirectory.SERVICE_NAME);
            if (services == null || services.Length == 0)
            {
                enabled = false;
                return;
            }


            CdsSubTestArgument arg = new CdsSubTestArgument();

            arg._Device         = device;
            arg._TestGroupState = new CdsTestGroupState();
            arg._TestGroup      = this;
            this.RunTests(null, arg);
        }
        /// <summary>
        /// Updates the <see cref="CdsSubTestArgument.SystemUpdateID"/> value with the specified ID.
        /// Checks the current value of the state variable and returns zero if the 
        /// specified ID matches the value of the state variable.
        /// </summary>
        /// <param name="updateID"></param>
        /// <param name="arg"></param>
        /// <returns>0=equal; 1=updateID is greater than device's state variable; -1=updateID is less than device's state variable</returns>
        public static int UpdateSystemUpdateID(uint updateID, CdsSubTestArgument arg, CdsSubTest sub)
        {
            arg._TestGroupState.SystemUpdateID = updateID;

            CpContentDirectory CDS = sub.GetCDS(arg._Device);

            uint updateID2 = CDS.SystemUpdateID;

            if (updateID > updateID2)
            {
                return 1;
            }
            else if (updateID < updateID2)
            {
                return -1;
            }

            return 0;
        }
        public override UPnPTestStates Run(ICollection otherSubTests, CdsSubTestArgument arg)
        {
            this._TestState = UPnPTestStates.Running;

            CpContentDirectory CDS = this.GetCDS(arg._Device);

            _Details = new CdsResult_GetSortCapabilities();
            _Details.SortCapabilities = null;

            try
            {
                if (CDS != null)
                {
                    DateTime start = System.DateTime.Now;
                    CDS.Sync_GetSortCapabilities(out _Details.SortCapabilities);
                    this.LogResponseTime(start, _Details, arg);
                }
            }
            catch (UPnPInvokeException ie)
            {
                arg.TestGroup.AddResult(this._Name + " test failed because of an invocation error: " + ie.Message);
                this._TestState = UPnPTestStates.Failed;
                return(this._TestState);
            }

            /* NKIDD - REMOVED BECAUSE EMPTY STRING IS LEGIT
             * if ((_Details.SortCapabilities == null) || (_Details.SortCapabilities == ""))
             * {
             *  arg.TestGroup.AddResult(this._Name + " test failed because result was empty or null string.");
             *  this._TestState = UPnPTestStates.Failed;
             *  return this._TestState;
             * }
             */

            arg._TestGroupState.SortCapabilities = _Details.SortCapabilities;
            arg.TestGroup.AddResult(this._Name + " test passed. Returned=\"" + _Details.SortCapabilities + "\".");
            this._TestState = UPnPTestStates.Pass;
            return(this._TestState);
        }
        public override UPnPTestStates Run(ICollection otherSubTests, CdsSubTestArgument arg)
        {
            this._TestState = UPnPTestStates.Running;

            CpContentDirectory CDS = this.GetCDS(arg._Device);
            _Details = new CdsResult_GetSortCapabilities();
            _Details.SortCapabilities = null;

            try
            {
                if (CDS != null)
                {
                    DateTime start = System.DateTime.Now;
                    CDS.Sync_GetSortCapabilities(out _Details.SortCapabilities);
                    this.LogResponseTime(start, _Details, arg);
                }
            }
            catch (UPnPInvokeException ie)
            {
                arg.TestGroup.AddResult(this._Name + " test failed because of an invocation error: " + ie.Message);
                this._TestState = UPnPTestStates.Failed;
                return this._TestState;
            }

            /* NKIDD - REMOVED BECAUSE EMPTY STRING IS LEGIT
            if ((_Details.SortCapabilities == null) || (_Details.SortCapabilities == ""))
            {
                arg.TestGroup.AddResult(this._Name + " test failed because result was empty or null string.");
                this._TestState = UPnPTestStates.Failed;
                return this._TestState;
            }
            */

            arg._TestGroupState.SortCapabilities = _Details.SortCapabilities;
            arg.TestGroup.AddResult(this._Name + " test passed. Returned=\"" + _Details.SortCapabilities + "\".");
            this._TestState = UPnPTestStates.Pass;
            return this._TestState;
        }
        public override UPnPTestStates Run(ICollection otherSubTests, CdsSubTestArgument arg)
        {
            // init basic stuff
            CpContentDirectory CDS = this.GetCDS(arg._Device);
            _Details = new CdsResult_BrowseAll();

            // set up a queue of containers to browse, starting with root container
            Queue C = new Queue();
            _Details.Root = new MediaContainer();
            _Details.Root.ID = "0";
            _Details.AllObjects.Add(_Details.Root);
            _Details.TotalContainers = 1;
            _Details.TotalItems = 0;
            C.Enqueue(_Details.Root);

            // if we have containers to browse, do so
            this._TestState = UPnPTestStates.Running;
            UPnPTestStates testResult = UPnPTestStates.Ready;
            arg._TestGroup.AddEvent(LogImportance.Remark, this.Name, "\""+this.Name + "\" started.");
            while (C.Count > 0)
            {
                IMediaContainer c = (IMediaContainer) C.Dequeue();

                this._ExpectedTestingTime = _Details.ExpectedTotalBrowseRequests * 30;
                arg.ActiveTests.UpdateTimeAndProgress( _Details.TotalBrowseRequests * 30);

                //
                // get the container's metadata
                //

                IUPnPMedia metadata;
                CdsBrowseSearchResults results = GetContainerMetadataAndValidate(c.ID, CDS, this, arg, _Details, out metadata);

                testResult = results.WorstError;

                if (testResult > UPnPTestStates.Warn)
                {
                    arg._TestGroup.AddEvent(LogImportance.Critical, this.Name, this.Name + " terminating because container metadata could not be obtained or the metadata was not CDS-compliant.");
                    testResult = UPnPTestStates.Failed;
                    this._TestState = testResult;
                    return this._TestState;
                }

                if (metadata != null)
                {
                    try
                    {
                        c.UpdateObject(metadata);
                        c.Tag = results.UpdateID;
                    }
                    catch (Exception e)
                    {
                        UpdateObjectError uoe = new UpdateObjectError();
                        uoe.UpdateThis = c;
                        uoe.Metadata = metadata;
                        throw new TestException("Critical error updating metadata of a container using UpdateObject()", uoe, e);
                    }
                }
                else
                {
                    string reason = "\"" +this.Name + "\" terminating because container metadata could not be cast into object form.";
                    arg._TestGroup.AddEvent(LogImportance.Critical, this.Name, reason);
                    arg._TestGroup.AddResult("\""+this.Name + "\" test failed. " + reason);
                    testResult = UPnPTestStates.Failed;
                    this._TestState = testResult;
                    return this._TestState;
                }

                //
                // Now get the container's children
                //
                ArrayList children = new ArrayList();
                try
                {
                    children = GetContainerChildrenAndValidate(c, CDS, this, arg, _Details, C);

                    if ((_Details.LargestContainer == null) || (children.Count > _Details.LargestContainer.ChildCount))
                    {
                        _Details.LargestContainer = c;
                    }
                }
                catch (TerminateEarly te)
                {
                    string reason = "\"" +this.Name + "\" terminating early. Reason => " + te.Message;
                    arg._TestGroup.AddEvent(LogImportance.Critical, this.Name, reason);
                    arg._TestGroup.AddResult("\""+this.Name + "\" test failed. " + reason);
                    testResult = UPnPTestStates.Failed;
                    this._TestState = testResult;
                    return this._TestState;
                }
            }

            if (testResult >= UPnPTestStates.Failed)
            {
                throw new TestException("Execution should not reach this code if testResult is WARN or worse.", testResult);
            }

            if (testResult == UPnPTestStates.Ready)
            {
                throw new TestException("We should not return Ready state.", testResult);
            }

            StringBuilder sb = new StringBuilder();
            sb.Append("\""+this._Name + "\" test finished");

            if (testResult == UPnPTestStates.Warn)
            {
                sb.Append(" with warnings");
            }

            sb.AppendFormat(" and found {0}/{1}/{2} TotalObjects/TotalContainers/TotalItems.", _Details.AllObjects.Count, _Details.TotalContainers, _Details.TotalItems);

            arg.TestGroup.AddResult(sb.ToString());
            arg._TestGroup.AddEvent(LogImportance.Remark, this.Name, this.Name + " completed.");

            this._TestState = testResult;

            if (this._TestState <= UPnPTestStates.Warn)
            {
                if (_Details.TotalBrowseRequests != _Details.ExpectedTotalBrowseRequests)
                {
                    throw new TestException("TotalBrowseRequests="+_Details.TotalBrowseRequests.ToString()+" ExpectedTotal="+_Details.ExpectedTotalBrowseRequests.ToString(), _Details);
                }
            }
            return this._TestState;
        }
        /// <summary>
        /// Tests the container with BrowseDirectChildren and different ranges.
        /// </summary>
        /// <param name="c"></param>
        /// <param name="test"></param>
        /// <param name="arg"></param>
        /// <param name="cds"></param>
        /// <param name="stats"></param>
        /// <returns></returns>
        public static CdsBrowseSearchResults TestContainerRanges(IMediaContainer c, CdsSubTest test, CdsSubTestArgument arg, CpContentDirectory cds, CdsResult_BrowseStats stats)
        {
            CdsBrowseSearchResults r = new CdsBrowseSearchResults();

            try
            {
                BrowseInput input = new BrowseInput();
                input.BrowseFlag = CpContentDirectory.Enum_A_ARG_TYPE_BrowseFlag.BROWSEDIRECTCHILDREN;
                input.Filter = "*";
                input.ObjectID = c.ID;
                input.SortCriteria = "";

                input.StartingIndex = 0;
                input.RequestedCount = 0;

                if (c.CompleteList.Count != c.ChildCount)
                {
                    throw new TestException("\""+test.Name+"\" has c.CompleteList.Count=" +c.CompleteList.Count+ " but c.ChildCount=" +c.ChildCount+ ".", c);
                }

                //assume the test will pass, but worsen the result when we find errors
                r.SetError(UPnPTestStates.Pass);

                // test starting index = 0 to c.ChildCount+1
                // test requested count = 0 to c.ChildCoun+1
                for (uint start = 0; start < c.ChildCount+1; start++)
                {
                    for (uint requested = 0; requested < c.ChildCount+1; requested++)
                    {
                        uint start_requested = start+requested;
                        bool doBrowse = false;
                        int tenthCount = c.ChildCount / 10;
                        int quarterCount = c.ChildCount / 4;
                        if (quarterCount == 0)
                        {
                            quarterCount = 1;
                        }
                        if (tenthCount == 0)
                        {
                            tenthCount = 1;
                        }

                        if (start < LIMIT)
                        {
                            if (
                                (requested == 0) ||
                                (start_requested > c.ChildCount - LIMIT)
                                )
                            {
                                doBrowse = true;
                            }

                        }
                        else if (start >= c.ChildCount - LIMIT)
                        {
                            if (start_requested < c.ChildCount+LIMIT)
                            {
                                doBrowse = true;
                            }
                        }
                        else if ((start % quarterCount == 0) && (requested % tenthCount == 0))
                        {
                            doBrowse = true;
                        }

                        if (doBrowse == false)
                        {
                            //stats.TotalBrowseRequests++;
                            //arg.ActiveTests.UpdateTimeAndProgress(stats.TotalBrowseRequests * 300);
                        }
                        else
                        {
                            arg.ActiveTests.UpdateTimeAndProgress(stats.TotalBrowseRequests * 300);

                            input.StartingIndex = start;
                            input.RequestedCount = requested;
                            CdsBrowseSearchResults br;

                            br = Cds_BrowseAll.Browse(input, test, arg, cds, stats);

                            if (br.WorstError >= UPnPTestStates.Failed)
                            {
                                if (
                                    (input.StartingIndex < c.ChildCount)
                                    )
                                {
                                    throw new TerminateEarly("\"" + test.Name + "\" is terminating early because " +input.PrintBrowseParams()+ " returned with an error or had problems with the DIDL-Lite.");
                                }
                                else
                                {
                                    arg._TestGroup.AddEvent(LogImportance.High, test.Name, "\"" + test.Name + "\": Warning: " +input.PrintBrowseParams()+ " returned an error.");
                                    r.SetError(UPnPTestStates.Warn);
                                }
                            }

                            // check return values

                            if (br.NumberReturned != br.MediaObjects.Count)
                            {
                                throw new TerminateEarly("\""+test.Name+"\" did a "+ input.PrintBrowseParams() + " and the number of media objects instantiated from the DIDL-Lite (instantiated=" +br.MediaObjects.Count+ ") does not match NumberReturned=" +br.NumberReturned+".");
                            }

                            long expectedReturned;

                            if (input.StartingIndex == 0)
                            {
                                if (input.RequestedCount == 0)
                                {
                                    expectedReturned = c.ChildCount;
                                }
                                else if (input.RequestedCount > c.ChildCount)
                                {
                                    expectedReturned = c.ChildCount;
                                }
                                else if (input.RequestedCount <= c.ChildCount)
                                {
                                    expectedReturned = input.RequestedCount;
                                }
                                else
                                {
                                    throw new TestException("\""+test.Name+"\" should not reach here.", null);
                                }
                            }
                            else
                            {
                                if (input.RequestedCount == 0)
                                {
                                    expectedReturned = c.ChildCount - input.StartingIndex;
                                }
                                else
                                {
                                    expectedReturned = c.ChildCount - input.StartingIndex;

                                    if (expectedReturned > input.RequestedCount)
                                    {
                                        expectedReturned = input.RequestedCount;
                                    }
                                }
                            }

                            if ((expectedReturned < 0) || (expectedReturned > c.ChildCount))
                            {
                                throw new TestException("\""+test.Name+"\" did a " + input.PrintBrowseParams() + " and the expected number of media objects is invalid=" + expectedReturned + ".", br);
                            }

                            if (br.NumberReturned != expectedReturned)
                            {
                                throw new TerminateEarly("\""+test.Name+"\" did a "+ input.PrintBrowseParams() + " and NumberReturned=" +br.NumberReturned+ " but test expects " +expectedReturned+ " child objects according to results from a prerequisite test.");
                            }

                            if (br.TotalMatches != c.ChildCount)
                            {
                                throw new TerminateEarly("\""+test.Name+"\" did a "+ input.PrintBrowseParams() + " and TotalMatches=" +br.TotalMatches+ " but test found " +c.ChildCount+ " child objects in a prerequisite test.");
                            }

                            uint cUpdateID = 0;

                            try
                            {
                                cUpdateID = (uint) c.Tag;
                            }
                            catch (Exception ce)
                            {
                                throw new TestException("\""+test.Name+"\" could not cast c.Tag into a uint value", null, ce);
                            }

                            if (br.UpdateID != cUpdateID)
                            {
                                throw new TerminateEarly("\""+test.Name+"\" did a "+ input.PrintBrowseParams() + " and UpdateID=" +br.UpdateID+ " but test expected=" +cUpdateID+ " as found in a prerequisite test.");
                            }

                            arg.TestGroup.AddEvent(LogImportance.Remark, test.Name, "\""+test.Name+"\" did a " +input.PrintBrowseParams()+ " and encountered no errors in the results.");
                            arg.ActiveTests.UpdateTimeAndProgress(stats.TotalBrowseRequests * 300);
                        }
                    }
                }
            }
            catch (TerminateEarly te)
            {
                arg._TestGroup.AddEvent(LogImportance.Critical, test.Name, test.Name + " is terminating early because of the following error: " + te.Message);
                r.SetError(UPnPTestStates.Failed);
                return r;
            }

            if (r.WorstError > UPnPTestStates.Warn)
            {
                throw new TestException("\"" + test.Name + "\" should not reach this code if the result is worse than " + UPnPTestStates.Warn.ToString() + ".", null);
            }

            return r;
        }
        /// <summary>
        /// Tests the container with BrowseDirectChildren and different ranges.
        /// </summary>
        /// <param name="c"></param>
        /// <param name="test"></param>
        /// <param name="arg"></param>
        /// <param name="cds"></param>
        /// <param name="stats"></param>
        /// <returns></returns>
        public static CdsBrowseSearchResults TestContainerRanges(IMediaContainer c, CdsSubTest test, CdsSubTestArgument arg, CpContentDirectory cds, CdsResult_BrowseStats stats)
        {
            CdsBrowseSearchResults r = new CdsBrowseSearchResults();

            try
            {
                BrowseInput input = new BrowseInput();
                input.BrowseFlag   = CpContentDirectory.Enum_A_ARG_TYPE_BrowseFlag.BROWSEDIRECTCHILDREN;
                input.Filter       = "*";
                input.ObjectID     = c.ID;
                input.SortCriteria = "";

                input.StartingIndex  = 0;
                input.RequestedCount = 0;

                if (c.CompleteList.Count != c.ChildCount)
                {
                    throw new TestException("\"" + test.Name + "\" has c.CompleteList.Count=" + c.CompleteList.Count + " but c.ChildCount=" + c.ChildCount + ".", c);
                }

                //assume the test will pass, but worsen the result when we find errors
                r.SetError(UPnPTestStates.Pass);

                // test starting index = 0 to c.ChildCount+1
                // test requested count = 0 to c.ChildCoun+1
                for (uint start = 0; start < c.ChildCount + 1; start++)
                {
                    for (uint requested = 0; requested < c.ChildCount + 1; requested++)
                    {
                        uint start_requested = start + requested;
                        bool doBrowse        = false;
                        int  tenthCount      = c.ChildCount / 10;
                        int  quarterCount    = c.ChildCount / 4;
                        if (quarterCount == 0)
                        {
                            quarterCount = 1;
                        }
                        if (tenthCount == 0)
                        {
                            tenthCount = 1;
                        }

                        if (start < LIMIT)
                        {
                            if (
                                (requested == 0) ||
                                (start_requested > c.ChildCount - LIMIT)
                                )
                            {
                                doBrowse = true;
                            }
                        }
                        else if (start >= c.ChildCount - LIMIT)
                        {
                            if (start_requested < c.ChildCount + LIMIT)
                            {
                                doBrowse = true;
                            }
                        }
                        else if ((start % quarterCount == 0) && (requested % tenthCount == 0))
                        {
                            doBrowse = true;
                        }


                        if (doBrowse == false)
                        {
                            //stats.TotalBrowseRequests++;
                            //arg.ActiveTests.UpdateTimeAndProgress(stats.TotalBrowseRequests * 300);
                        }
                        else
                        {
                            arg.ActiveTests.UpdateTimeAndProgress(stats.TotalBrowseRequests * 300);

                            input.StartingIndex  = start;
                            input.RequestedCount = requested;
                            CdsBrowseSearchResults br;

                            br = Cds_BrowseAll.Browse(input, test, arg, cds, stats);

                            if (br.WorstError >= UPnPTestStates.Failed)
                            {
                                if (
                                    (input.StartingIndex < c.ChildCount)
                                    )
                                {
                                    throw new TerminateEarly("\"" + test.Name + "\" is terminating early because " + input.PrintBrowseParams() + " returned with an error or had problems with the DIDL-Lite.");
                                }
                                else
                                {
                                    arg._TestGroup.AddEvent(LogImportance.High, test.Name, "\"" + test.Name + "\": Warning: " + input.PrintBrowseParams() + " returned an error.");
                                    r.SetError(UPnPTestStates.Warn);
                                }
                            }

                            // check return values

                            if (br.NumberReturned != br.MediaObjects.Count)
                            {
                                throw new TerminateEarly("\"" + test.Name + "\" did a " + input.PrintBrowseParams() + " and the number of media objects instantiated from the DIDL-Lite (instantiated=" + br.MediaObjects.Count + ") does not match NumberReturned=" + br.NumberReturned + ".");
                            }

                            long expectedReturned;

                            if (input.StartingIndex == 0)
                            {
                                if (input.RequestedCount == 0)
                                {
                                    expectedReturned = c.ChildCount;
                                }
                                else if (input.RequestedCount > c.ChildCount)
                                {
                                    expectedReturned = c.ChildCount;
                                }
                                else if (input.RequestedCount <= c.ChildCount)
                                {
                                    expectedReturned = input.RequestedCount;
                                }
                                else
                                {
                                    throw new TestException("\"" + test.Name + "\" should not reach here.", null);
                                }
                            }
                            else
                            {
                                if (input.RequestedCount == 0)
                                {
                                    expectedReturned = c.ChildCount - input.StartingIndex;
                                }
                                else
                                {
                                    expectedReturned = c.ChildCount - input.StartingIndex;

                                    if (expectedReturned > input.RequestedCount)
                                    {
                                        expectedReturned = input.RequestedCount;
                                    }
                                }
                            }

                            if ((expectedReturned < 0) || (expectedReturned > c.ChildCount))
                            {
                                throw new TestException("\"" + test.Name + "\" did a " + input.PrintBrowseParams() + " and the expected number of media objects is invalid=" + expectedReturned + ".", br);
                            }

                            if (br.NumberReturned != expectedReturned)
                            {
                                throw new TerminateEarly("\"" + test.Name + "\" did a " + input.PrintBrowseParams() + " and NumberReturned=" + br.NumberReturned + " but test expects " + expectedReturned + " child objects according to results from a prerequisite test.");
                            }

                            if (br.TotalMatches != c.ChildCount)
                            {
                                throw new TerminateEarly("\"" + test.Name + "\" did a " + input.PrintBrowseParams() + " and TotalMatches=" + br.TotalMatches + " but test found " + c.ChildCount + " child objects in a prerequisite test.");
                            }

                            uint cUpdateID = 0;

                            try
                            {
                                cUpdateID = (uint)c.Tag;
                            }
                            catch (Exception ce)
                            {
                                throw new TestException("\"" + test.Name + "\" could not cast c.Tag into a uint value", null, ce);
                            }

                            if (br.UpdateID != cUpdateID)
                            {
                                throw new TerminateEarly("\"" + test.Name + "\" did a " + input.PrintBrowseParams() + " and UpdateID=" + br.UpdateID + " but test expected=" + cUpdateID + " as found in a prerequisite test.");
                            }

                            arg.TestGroup.AddEvent(LogImportance.Remark, test.Name, "\"" + test.Name + "\" did a " + input.PrintBrowseParams() + " and encountered no errors in the results.");
                            arg.ActiveTests.UpdateTimeAndProgress(stats.TotalBrowseRequests * 300);
                        }
                    }
                }
            }
            catch (TerminateEarly te)
            {
                arg._TestGroup.AddEvent(LogImportance.Critical, test.Name, test.Name + " is terminating early because of the following error: " + te.Message);
                r.SetError(UPnPTestStates.Failed);
                return(r);
            }

            if (r.WorstError > UPnPTestStates.Warn)
            {
                throw new TestException("\"" + test.Name + "\" should not reach this code if the result is worse than " + UPnPTestStates.Warn.ToString() + ".", null);
            }

            return(r);
        }
        /// <summary>
        /// Tests filters for metadata.
        /// </summary>
        /// <param name="testThis"></param>
        /// <param name="test"></param>
        /// <param name="arg"></param>
        /// <param name="cds"></param>
        /// <param name="stats"></param>
        /// <returns></returns>
        public static CdsBrowseSearchResults TestFiltersBrowseMetadata(IUPnPMedia testThis, CpContentDirectory.Enum_A_ARG_TYPE_BrowseFlag browseFlag, Cds_BrowseFilter test, CdsSubTestArgument arg, CpContentDirectory cds, CdsResult_BrowseFilter stats)
        {
            CdsBrowseSearchResults r = new CdsBrowseSearchResults();

            try
            {
                BrowseInput input = new BrowseInput();
                input.BrowseFlag = browseFlag;
                if (input.BrowseFlag == CpContentDirectory.Enum_A_ARG_TYPE_BrowseFlag.BROWSEMETADATA)
                {
                    input.ObjectID = testThis.ID;
                }
                else
                {
                    input.ObjectID = testThis.ParentID;
                }
                input.SortCriteria = "";

                input.StartingIndex  = 0;
                input.RequestedCount = 0;

                //assume the test will pass, but worsen the result when we find errors
                r.SetError(UPnPTestStates.Pass);

                ArrayList propNames = new ArrayList((ICollection)testThis.Properties.PropertyNames);

                // add property names related to resources
                propNames.Add(T[_DIDL.Res]);
                foreach (string str in MediaResource.GetPossibleAttributes())
                {
                    propNames.Add(T[_DIDL.Res] + "@" + str);
                    propNames.Add("@" + str);
                }
                propNames.Add(T[_DIDL.Desc]);

                if (propNames.Count != stats.NumberOfProperties)
                {
                    throw new TestException("Number of calculated metadata properties (" + propNames.Count + ") doesn't match number of actual metadata properties (" + propNames.Count + ") for testing.", stats);
                }

                test._Details.Filters = propNames;

                int inc = propNames.Count / 4;
                if (inc == 0)
                {
                    inc = 1;
                }

                for (int numProps = 0; numProps < propNames.Count; numProps++)
                {
                    for (int iProp = 0; iProp < propNames.Count; iProp += inc)
                    {
                        IList filterSettings = GetFilterSettings(propNames, numProps, iProp, iProp);

                        input.Filter = GetCSVString(filterSettings);

                        CdsBrowseSearchResults br;

                        arg.ActiveTests.UpdateTimeAndProgress(90 * stats.TotalBrowseRequests);

                        br = Cds_BrowseAll.Browse(input, test, arg, cds, stats);

                        if (br.WorstError >= UPnPTestStates.Failed)
                        {
                            StringBuilder teMsg = new StringBuilder();

                            teMsg.AppendFormat("\"{0}\" is terminating early because {1} returned with an error or had problems with the DIDL-Lite.", test.Name, input.PrintBrowseParams());
                            if (br.Result != "")
                            {
                                teMsg.AppendFormat(" Returned DIDL=\"{0}\".", br.Result);
                            }
                            throw new TerminateEarly(teMsg.ToString());
                        }
                        //							if (br.InvokeError != null)
                        //							{
                        //								throw new TerminateEarly("\"" + test.Name + "\" is terminating early because " +input.PrintBrowseParams()+ " returned with an error" + br.InvokeError.Message, br.InvokeError);
                        //							}

                        if (input.BrowseFlag == CpContentDirectory.Enum_A_ARG_TYPE_BrowseFlag.BROWSEMETADATA)
                        {
                            if (br.MediaObjects.Count != 1)
                            {
                                throw new TerminateEarly("\"" + test.Name + "\" is terminating early because " + input.PrintBrowseParams() + " did not return with exactly one media object in its DIDL-Lite response. DIDL-Lite => " + br.Result);
                            }

                            IUPnPMedia mo = (IUPnPMedia)br.MediaObjects[0];

                            CheckReturnedMetadata(mo, testThis, input, filterSettings, br, test);
                            arg.TestGroup.AddEvent(LogImportance.Remark, test.Name, "\"" + test.Name + "\" did a " + input.PrintBrowseParams() + " and encountered no errors in the results.");
                        }
                        else
                        {
                            IList childList = testThis.Parent.CompleteList;

                            foreach (IUPnPMedia gotChild in br.MediaObjects)
                            {
                                IUPnPMedia testAgainstChild = null;
                                foreach (IUPnPMedia child in childList)
                                {
                                    if (child.ID == gotChild.ID)
                                    {
                                        testAgainstChild = child;
                                        break;
                                    }
                                }
                                if (testAgainstChild == null)
                                {
                                    throw new TerminateEarly("\"" + test.Name + "\" is terminating early because " + input.PrintBrowseParams() + " returned media object with ID=\"" + gotChild.ID + "\", which was not a child object of containerID=\"" + input.ObjectID + "\" during a prerequisite test.");
                                }
                                CheckReturnedMetadata(gotChild, testAgainstChild, input, filterSettings, br, test);
                                arg.TestGroup.AddEvent(LogImportance.Remark, test.Name, "\"" + test.Name + "\" did a " + input.PrintBrowseParams() + " and encountered no errors in the results.");
                            }
                        }
                    }
                }
            }
            catch (TerminateEarly te)
            {
                string reason = "\"" + test.Name + "\" terminating early. Reason => " + te.Message;
                arg._TestGroup.AddEvent(LogImportance.Critical, test.Name, reason);

                r.SetError(UPnPTestStates.Failed);
                return(r);
            }

            if (r.WorstError > UPnPTestStates.Warn)
            {
                throw new TestException("\"" + test.Name + "\" should not reach this code if the result is worse than " + UPnPTestStates.Warn.ToString() + ".", null);
            }

            return(r);
        }
        public void CompareResultsAgainstExpected(CdsBrowseSearchResults br, IList expectedResults, ref UPnPTestStates state, CdsSubTestArgument arg, BrowseInput input, bool strictOrder)
        {
            if (br.WorstError >= UPnPTestStates.Failed)
            {
                throw new TerminateEarly("\"" + this.Name + "\" is terminating early because " +input.PrintBrowseParams()+ " returned with an error or had problems with the DIDL-Lite.");
            }
            else
            {
                if (br.MediaObjects.Count != expectedResults.Count)
                {
                    throw new TerminateEarly("\""+this.Name+"\" did a " +input.PrintBrowseParams()+ " and it should have returned "+expectedResults.Count+ " media objects. DIDL-Lite contained " +br.MediaObjects.Count+ " media objects. DIDL-Lite => " + br.Result);
                }

                bool warnResults = false;
                for (int i=0; i < br.MediaObjects.Count; i++)
                {

                    IUPnPMedia gotThis = (IUPnPMedia) br.MediaObjects[i];
                    IUPnPMedia expectedMedia = (IUPnPMedia) expectedResults[i];

                    if (gotThis.ID == expectedMedia.ID)
                    {
                        //arg.TestGroup.AddEvent(LogImportance.Remark, this.Name, "\""+this.Name+"\" did a " +input.PrintBrowseParams()+ " and encountered no errors in the results.");
                    }
                    else
                    {
                        bool failed = false;
                        if ((input.SortCriteria == null) || (input.SortCriteria == ""))
                        {
                            failed = true;
                        }
                        else
                        {
                            // Use this sorter to test for value-equality in situations where the expected order didn't match.
                            // We need to do this because two media objects may be value-equivalent according to a sorting
                            // algorithm, in which case there's no way to really distinguish what order they should be in.
                            IMediaSorter sorter2 = new MediaSorter(false, input.SortCriteria);

                            int cmp = sorter2.Compare(gotThis, expectedMedia);
                            if (cmp != 0)
                            {
                                arg.TestGroup.AddEvent(LogImportance.Medium, this.Name, "\""+this.Name+"\" found media object ID=\""+gotThis.ID+"\" when it expected to find \""+expectedMedia.ID+"\" and they are not equal in their sorted order.");
                                warnResults = true;
                            }
                            else
                            {
                                if (strictOrder == false)
                                {
                                    arg.TestGroup.AddEvent(LogImportance.Low, this.Name, "\""+this.Name+"\" found media object ID=\""+gotThis.ID+"\" when it expected to find \""+expectedMedia.ID+"\" but since they are effectively value-equivalent, the ordering is OK.");
                                }
                                else
                                {
                                    failed = true;
                                }
                            }
                        }

                        if (failed)
                        {
                            StringBuilder msg = new StringBuilder();
                            msg.AppendFormat("\"{0}\" did a {1} and the order of object ID's in the result conflicts with previous browse requests.");
                            msg.AppendFormat("\r\n\r\nReceived objects in order by ID: ");
                            int z = 0;
                            foreach (IUPnPMedia em in br.MediaObjects)
                            {
                                if (z > 0)
                                {
                                    msg.Append(",");
                                }
                                msg.AppendFormat("\"{0}\"", em.ID);
                                z++;
                            }
                            msg.Append("\r\n\r\nThe expected order by ID is: ");
                            z = 0;
                            foreach (IUPnPMedia em in expectedResults)
                            {
                                if (z > 0)
                                {
                                    msg.Append(",");
                                }
                                msg.AppendFormat("\"{0}\"", em.ID);
                                z++;
                            }
                            msg.AppendFormat(".\r\n\r\nDIDL-Lite ==> {0}", br.Result);
                            throw new TerminateEarly(msg.ToString());
                        }
                    }
                }

                if (warnResults == false)
                {
                    arg.TestGroup.AddEvent(LogImportance.Remark, this.Name, "\""+this.Name+"\" did a " +input.PrintBrowseParams()+ " and encountered no errors or warnings in the results.");
                }
                else
                {
                    StringBuilder msg = new StringBuilder();
                    msg.AppendFormat("WARNING: \"{0}\" did a {1} and \r\nreceived results in the following order by ID: ", this.Name, input.PrintBrowseParams());
                    int z = 0;
                    foreach (IUPnPMedia em in br.MediaObjects)
                    {
                        if (z > 0)
                        {
                            msg.Append(",");
                        }
                        msg.AppendFormat("\"{0}\"", em.ID);
                        z++;
                    }
                    msg.Append("\r\n\r\nThe expected order by ID is: ");
                    z = 0;
                    foreach (IUPnPMedia em in expectedResults)
                    {
                        if (z > 0)
                        {
                            msg.Append(",");
                        }
                        msg.AppendFormat("\"{0}\"", em.ID);
                        z++;
                    }
                    msg.AppendFormat(".\r\n\r\nDIDL-Lite ==> {0}", br.Result);
                    // warn
                    state = UPnPTestStates.Warn;
                    arg._TestGroup.AddEvent(LogImportance.Medium, this.Name, msg.ToString());
                }
            }
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="parent"></param>
        /// <param name="cds"></param>
        /// <param name="test"></param>
        /// <param name="arg"></param>
        /// <param name="details"></param>
        /// <param name="C"></param>
        /// <returns></returns>
        /// <exception cref="TerminateEarly">
        /// </exception>
        public static ArrayList GetContainerChildrenAndValidate(IMediaContainer parent, CpContentDirectory cds, CdsSubTest test, CdsSubTestArgument arg, CdsResult_BrowseAll details, Queue C)
        {
            uint totalExpected = uint.MaxValue;
            uint currentChild  = 0;

            ArrayList children = new ArrayList();

            while (currentChild < totalExpected)
            {
                BrowseInput input = new BrowseInput();
                input.ObjectID       = parent.ID;
                input.BrowseFlag     = CpContentDirectory.Enum_A_ARG_TYPE_BrowseFlag.BROWSEDIRECTCHILDREN;
                input.Filter         = "*";
                input.StartingIndex  = currentChild;
                input.RequestedCount = 1;
                input.SortCriteria   = "";

                string containerID = parent.ID;

                if (currentChild == 0)
                {
                    test.SetExpectedTestingTime((++details.ExpectedTotalBrowseRequests) * 30);
                    arg.ActiveTests.UpdateTimeAndProgress(details.TotalBrowseRequests * 30);
                }

                CdsBrowseSearchResults results = Browse(input, test, arg, cds, details);

                test.SetExpectedTestingTime((details.ExpectedTotalBrowseRequests) * 30);
                arg.ActiveTests.UpdateTimeAndProgress((details.TotalBrowseRequests) * 30);

                if (results.WorstError >= UPnPTestStates.Failed)
                {
                    throw new TerminateEarly("\"" + test.Name + "\" is terminating early because " + input.PrintBrowseParams() + " returned with an error or had problems with the DIDL-Lite.");
                }
                else
                {
                    if (results.NumberReturned != 1)
                    {
                        if (currentChild != 0)
                        {
                            results.SetError(UPnPTestStates.Failed);
                            arg._TestGroup.AddEvent(LogImportance.Low, test.Name, "\"" + test.Name + "\": " + input.PrintBrowseParams() + " returned NumberReturned=" + results.NumberReturned + " when it should logically be 1.");
                        }
                    }

                    if (results.TotalMatches != totalExpected)
                    {
                        if (currentChild != 0)
                        {
                            results.SetError(UPnPTestStates.Failed);
                            arg._TestGroup.AddEvent(LogImportance.Critical, test.Name, "\"" + test.Name + "\": " + input.PrintBrowseParams() + " returned TotalMatches=" + results.TotalMatches + " when it should logically be " + totalExpected + " as reported in an earlier Browse request. This portion of the test requires that a MediaServer device not be in a state where its content hierarchy will change.");
                        }
                        else
                        {
                            totalExpected = results.TotalMatches;
                            if (totalExpected > 0)
                            {
                                details.ExpectedTotalBrowseRequests += ((int)results.TotalMatches * 2) - 1;
                                test.SetExpectedTestingTime((details.ExpectedTotalBrowseRequests) * 30);
                                arg.ActiveTests.UpdateTimeAndProgress(details.TotalBrowseRequests * 30);
                            }
                        }
                    }

                    if (results.MediaObjects != null)
                    {
                        if (results.MediaObjects.Count == 1)
                        {
                            IUPnPMedia child = results.MediaObjects[0] as IUPnPMedia;

                            if (child == null)
                            {
                                throw new TestException("\"" + test.Name + "\"" + " has a TEST LOGIC ERROR. Browse returned without errors but the child object's metadata is not stored in an IUPnPMedia object. The offending type is " + results.MediaObjects[0].GetType().ToString(), results.MediaObjects[0]);
                            }

                            // ensure no duplicates in object ID
                            foreach (IUPnPMedia previousChild in details.AllObjects)
                            {
                                if (previousChild.ID == child.ID)
                                {
                                    string msg = "\"" + test.Name + "\": " + input.PrintBrowseParams() + " returned an object with ID=\"" + child.ID + "\" which conflicts with a previously seen media object in ParentContainerID=\"" + previousChild.ParentID + "\".";
                                    arg._TestGroup.AddEvent(LogImportance.Critical, test.Name, msg);
                                    throw new TerminateEarly(msg);
                                }
                            }

                            // ensure updateID is the same between BrowseDirectChildren and earlier BrowseMetadata.

                            try
                            {
                                uint previousUpdateID = (uint)parent.Tag;
                                if (results.UpdateID != previousUpdateID)
                                {
                                    string msg = "\"" + test.Name + "\": " + input.PrintBrowseParams() + " returned an UpdateID=" + results.UpdateID + " whilst an UpdateID=" + previousUpdateID + " was obtained in a previous call for ContainerID=\"" + parent.ID + "\" with BrowseMetadata.";
                                    arg._TestGroup.AddEvent(LogImportance.Critical, test.Name, msg);
                                    throw new TerminateEarly(msg);
                                }
                            }
                            catch (TerminateEarly te)
                            {
                                throw te;
                            }
                            catch (Exception e)
                            {
                                throw new TestException(test.Name + " has a TEST LOGIC ERROR. Error comparing UpdateID values", parent, e);
                            }

                            // add the child to lists: C, parent's child list, and Allobjects
                            try
                            {
                                parent.AddObject(child, false);
                            }
                            catch (Exception e)
                            {
                                AddObjectError aoe = new AddObjectError();
                                aoe.Parent = parent;
                                aoe.Child  = child;
                                throw new TestException(test.Name + " has a TEST LOGIC ERROR. Browse returned without errors but the child object could not be added to its parent.", aoe, e);
                            }

                            details.AllObjects.Add(child);
                            children.Add(child);
                            if (child.IsContainer)
                            {
                                C.Enqueue(child);
                                details.TotalContainers++;
                            }
                            else
                            {
                                details.TotalItems++;
                            }

                            //
                            // Do a BrowseMetadata and check to see if the XML values are the same.
                            //

                            CdsBrowseSearchResults compareResults = CheckMetadata(child, cds, test, arg, details);

                            if (compareResults.InvokeError != null)
                            {
                                arg._TestGroup.AddEvent(LogImportance.High, test.Name, test.Name + ": Browse(BrowseDirectChildren,StartingIndex=" + currentChild + ",RequestedCount=0) on ContainerID=[" + containerID + "] succeeded with warnings because a BrowseMetadata request was rejected by the CDS.");
                            }
                            else if (compareResults.ResultErrors.Count > 0)
                            {
                                string msg = "\"" + test.Name + "\": " + input.PrintBrowseParams() + " failed because a BrowseMetadata request succeeded but the DIDL-Lite could not be represented in object form. Invalid DIDL-Lite is most likely the cause.";
                                arg._TestGroup.AddEvent(LogImportance.Critical, test.Name, msg);
                                throw new TerminateEarly(msg);
                            }
                            else if (compareResults.WorstError >= UPnPTestStates.Failed)
                            {
                                string msg = "\"" + test.Name + "\": " + input.PrintBrowseParams() + " failed because one or more child object's failed a comparison of results between BrowseDirectChildren and BrowseMetadata or encountered some other critical error in that process.";
                                arg._TestGroup.AddEvent(LogImportance.Critical, test.Name, msg);
                                throw new TerminateEarly(msg);
                            }
                            else
                            {
                                //string msg = "\"" + test.Name + "\": " + input.PrintBrowseParams() + " succeeded.";
                                //arg._TestGroup.AddEvent(LogImportance.Remark, test.Name, msg);
                            }

                            //
                            // Track the metadata properties found so far
                            // as we may use them in Browse SortCriteria
                            //

                            // standard top-level attributes
                            Tags T = Tags.GetInstance();
                            AddTo(details.PropertyNames, "@" + T[_ATTRIB.id]);
                            AddTo(details.PropertyNames, "@" + T[_ATTRIB.parentID]);
                            AddTo(details.PropertyNames, "@" + T[_ATTRIB.restricted]);
                            if (child.IsContainer)
                            {
                                if (child.IsSearchable)
                                {
                                    AddTo(details.PropertyNames, "@" + T[_ATTRIB.searchable]);
                                    AddTo(details.PropertyNames, T[_DIDL.Container] + "@" + T[_ATTRIB.searchable]);
                                }

                                AddTo(details.PropertyNames, T[_DIDL.Container] + "@" + T[_ATTRIB.id]);
                                AddTo(details.PropertyNames, T[_DIDL.Container] + "@" + T[_ATTRIB.parentID]);
                                AddTo(details.PropertyNames, T[_DIDL.Container] + "@" + T[_ATTRIB.restricted]);
                            }
                            else if (child.IsItem)
                            {
                                if (child.IsReference)
                                {
                                    AddTo(details.PropertyNames, "@" + T[_ATTRIB.refID]);
                                    AddTo(details.PropertyNames, T[_DIDL.Item] + "@" + T[_ATTRIB.refID]);
                                }

                                AddTo(details.PropertyNames, T[_DIDL.Item] + "@" + T[_ATTRIB.id]);
                                AddTo(details.PropertyNames, T[_DIDL.Item] + "@" + T[_ATTRIB.parentID]);
                                AddTo(details.PropertyNames, T[_DIDL.Item] + "@" + T[_ATTRIB.restricted]);
                            }

                            // standard metadata
                            IMediaProperties properties    = child.MergedProperties;
                            IList            propertyNames = properties.PropertyNames;
                            foreach (string propertyName in propertyNames)
                            {
                                if (details.PropertyNames.Contains(propertyName) == false)
                                {
                                    details.PropertyNames.Add(propertyName);

                                    // add attributes if they are not added
                                    IList propertyValues = properties[propertyName];
                                    foreach (ICdsElement val in propertyValues)
                                    {
                                        ICollection attributes = val.ValidAttributes;
                                        foreach (string attribName in attributes)
                                        {
                                            StringBuilder sbpn = new StringBuilder();
                                            sbpn.AppendFormat("{0}@{1}", propertyName, attribName);
                                            string fullAttribName = sbpn.ToString();
                                            AddTo(details.PropertyNames, fullAttribName);
                                        }
                                    }
                                }

                                // resources
                                IList resources = child.MergedResources;
                                foreach (IMediaResource res in resources)
                                {
                                    ICollection attributes = res.ValidAttributes;
                                    foreach (string attribName in attributes)
                                    {
                                        string name1 = "res@" + attribName;
                                        string name2 = "@" + attribName;

                                        AddTo(details.PropertyNames, name1);
                                        AddTo(details.PropertyNames, name2);
                                    }
                                }

                                if (resources.Count > 0)
                                {
                                    AddTo(details.PropertyNames, T[_DIDL.Res]);
                                }
                            }
                        }
                        else
                        {
                            if (results.TotalMatches > 0)
                            {
                                results.SetError(UPnPTestStates.Failed);
                                string msg = "\"" + test.Name + "\": " + input.PrintBrowseParams() + " did not yield exactly one CDS-compliant media object in its result. Instantiated a total of " + results.MediaObjects.Count + " media objects.";
                                arg._TestGroup.AddEvent(LogImportance.Critical, test.Name, msg);
                                throw new TerminateEarly(msg);
                            }
                        }
                    }
                    else
                    {
                        throw new TestException(test.Name + " has a TEST LOGIC ERROR. Browse returned without errors but no media objects were instantiated.", null);
                    }
                }

                currentChild++;
            }

            return(children);
        }
Esempio n. 16
0
 protected void LogAverageUnitResponseTime(long averageTime, CdsTestResult result, CdsSubTestArgument arg)
 {
     result.AverageUnitResponseTime = averageTime;
     arg._TestGroup.AddEvent(LogImportance.Remark, this._Name, this._Name + " average unit response time: " + averageTime.ToString() + "ms" + result.UnitDescription);
 }
        /// <summary>
        /// Performs a Browse invocation.
        /// </summary>
        /// <param name="input"></param>
        /// <param name="test"></param>
        /// <param name="arg"></param>
        /// <param name="cds"></param>
        /// <param name="stats"></param>
        /// <returns></returns>
        public static CdsBrowseSearchResults Browse(BrowseInput input, CdsSubTest test, CdsSubTestArgument arg, CpContentDirectory cds, CdsResult_BrowseStats stats)
        {
            CdsBrowseSearchResults results = new CdsBrowseSearchResults();

            results.SetError(UPnPTestStates.Pass);
            results.ResultErrors = new ArrayList();

            arg._TestGroup.AddEvent(LogImportance.Remark, test.Name, "\"" + test.Name + "\" about to do " + input.PrintBrowseParams() + ".");
            try
            {
                cds.Sync_Browse(input.ObjectID, input.BrowseFlag, input.Filter, input.StartingIndex, input.RequestedCount, input.SortCriteria, out results.Result, out results.NumberReturned, out results.TotalMatches, out results.UpdateID);
            }
            catch (UPnPInvokeException error)
            {
                results.InvokeError = error;
            }

            if (results.InvokeError == null)
            {
                arg._TestGroup.AddEvent(LogImportance.Remark, test.Name, "\"" + test.Name + "\" completed " + input.PrintBrowseParams() + " with no errors returned by the device.");
            }
            else
            {
                arg._TestGroup.AddEvent(LogImportance.Remark, test.Name, "\"" + test.Name + "\" completed " + input.PrintBrowseParams() + " with the device returning an error.");
            }

            stats.TotalBrowseRequests++;
            ArrayList branches = null;

            if (results.InvokeError == null)
            {
                try
                {
                    if (results.Result != null)
                    {
                        if (results.Result != "")
                        {
                            bool schemaOK = CheckDidlLiteSchema(results.Result);

                            if (schemaOK)
                            {
                                results.MediaObjects = branches = MediaBuilder.BuildMediaBranches(results.Result, typeof(MediaItem), typeof(MediaContainer), true);

                                if (branches.Count != results.NumberReturned)
                                {
                                    results.ResultErrors.Add(new CdsException(input.PrintBrowseParams() + " has the \"Result\" argument indicating the presence of " + branches.Count + " media objects but the request returned NumberReturned=" + results.NumberReturned + "."));
                                }

                                if (input.BrowseFlag == CpContentDirectory.Enum_A_ARG_TYPE_BrowseFlag.BROWSEMETADATA)
                                {
                                    if (branches.Count != 1)
                                    {
                                        results.ResultErrors.Add(new CdsException(input.PrintBrowseParams() + " has the \"Result\" argument indicating the presence of " + branches.Count + " media objects but the request should have only returned 1 media object."));
                                    }
                                }

                                foreach (IUPnPMedia mobj in branches)
                                {
                                    IMediaContainer imc = mobj as IMediaContainer;

                                    if (imc != null)
                                    {
                                        if (imc.CompleteList.Count > 0)
                                        {
                                            StringBuilder offendingList = new StringBuilder();
                                            int           offenses      = 0;
                                            foreach (IUPnPMedia offending in imc.CompleteList)
                                            {
                                                if (offenses > 0)
                                                {
                                                    offendingList.Append(",");
                                                }
                                                offendingList.AppendFormat("\"{0}\"", offending.ID);
                                                offenses++;
                                            }
                                            results.ResultErrors.Add(new CdsException(input.PrintBrowseParams() + " has the \"Result\" argument with a declared container (ID=\"" + imc.ID + "\") element that also includes its immediate children. Illegally declared media objects in the response are: " + offendingList.ToString()));
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                catch (Exception error2)
                {
                    results.ResultErrors.Add(error2);
                    if (results.MediaObjects == null)
                    {
                        results.MediaObjects = new ArrayList();
                    }
                }
            }

            // log any errors
            if ((results.InvokeError != null) || (results.ResultErrors.Count > 0))
            {
                LogErrors(arg._TestGroup, test, input, "Browse", results.InvokeError, results.ResultErrors);
                results.SetError(UPnPTestStates.Failed);
            }

            return(results);
        }
        public override UPnPTestStates Run(ICollection otherSubTests, CdsSubTestArgument arg)
        {
            // init basic stuff
            CpContentDirectory CDS = this.GetCDS(arg._Device);

            _Details = new CdsResult_BrowseAll();

            // set up a queue of containers to browse, starting with root container
            Queue C = new Queue();

            _Details.Root    = new MediaContainer();
            _Details.Root.ID = "0";
            _Details.AllObjects.Add(_Details.Root);
            _Details.TotalContainers = 1;
            _Details.TotalItems      = 0;
            C.Enqueue(_Details.Root);

            // if we have containers to browse, do so
            this._TestState = UPnPTestStates.Running;
            UPnPTestStates testResult = UPnPTestStates.Ready;

            arg._TestGroup.AddEvent(LogImportance.Remark, this.Name, "\"" + this.Name + "\" started.");
            while (C.Count > 0)
            {
                IMediaContainer c = (IMediaContainer)C.Dequeue();

                this._ExpectedTestingTime = _Details.ExpectedTotalBrowseRequests * 30;
                arg.ActiveTests.UpdateTimeAndProgress(_Details.TotalBrowseRequests * 30);

                //
                // get the container's metadata
                //

                IUPnPMedia             metadata;
                CdsBrowseSearchResults results = GetContainerMetadataAndValidate(c.ID, CDS, this, arg, _Details, out metadata);

                testResult = results.WorstError;

                if (testResult > UPnPTestStates.Warn)
                {
                    arg._TestGroup.AddEvent(LogImportance.Critical, this.Name, this.Name + " terminating because container metadata could not be obtained or the metadata was not CDS-compliant.");
                    testResult      = UPnPTestStates.Failed;
                    this._TestState = testResult;
                    return(this._TestState);
                }

                if (metadata != null)
                {
                    try
                    {
                        c.UpdateObject(metadata);
                        c.Tag = results.UpdateID;
                    }
                    catch (Exception e)
                    {
                        UpdateObjectError uoe = new UpdateObjectError();
                        uoe.UpdateThis = c;
                        uoe.Metadata   = metadata;
                        throw new TestException("Critical error updating metadata of a container using UpdateObject()", uoe, e);
                    }
                }
                else
                {
                    string reason = "\"" + this.Name + "\" terminating because container metadata could not be cast into object form.";
                    arg._TestGroup.AddEvent(LogImportance.Critical, this.Name, reason);
                    arg._TestGroup.AddResult("\"" + this.Name + "\" test failed. " + reason);
                    testResult      = UPnPTestStates.Failed;
                    this._TestState = testResult;
                    return(this._TestState);
                }

                //
                // Now get the container's children
                //
                ArrayList children = new ArrayList();
                try
                {
                    children = GetContainerChildrenAndValidate(c, CDS, this, arg, _Details, C);

                    if ((_Details.LargestContainer == null) || (children.Count > _Details.LargestContainer.ChildCount))
                    {
                        _Details.LargestContainer = c;
                    }
                }
                catch (TerminateEarly te)
                {
                    string reason = "\"" + this.Name + "\" terminating early. Reason => " + te.Message;
                    arg._TestGroup.AddEvent(LogImportance.Critical, this.Name, reason);
                    arg._TestGroup.AddResult("\"" + this.Name + "\" test failed. " + reason);
                    testResult      = UPnPTestStates.Failed;
                    this._TestState = testResult;
                    return(this._TestState);
                }
            }

            if (testResult >= UPnPTestStates.Failed)
            {
                throw new TestException("Execution should not reach this code if testResult is WARN or worse.", testResult);
            }

            if (testResult == UPnPTestStates.Ready)
            {
                throw new TestException("We should not return Ready state.", testResult);
            }

            StringBuilder sb = new StringBuilder();

            sb.Append("\"" + this._Name + "\" test finished");

            if (testResult == UPnPTestStates.Warn)
            {
                sb.Append(" with warnings");
            }

            sb.AppendFormat(" and found {0}/{1}/{2} TotalObjects/TotalContainers/TotalItems.", _Details.AllObjects.Count, _Details.TotalContainers, _Details.TotalItems);

            arg.TestGroup.AddResult(sb.ToString());
            arg._TestGroup.AddEvent(LogImportance.Remark, this.Name, this.Name + " completed.");

            this._TestState = testResult;

            if (this._TestState <= UPnPTestStates.Warn)
            {
                if (_Details.TotalBrowseRequests != _Details.ExpectedTotalBrowseRequests)
                {
                    throw new TestException("TotalBrowseRequests=" + _Details.TotalBrowseRequests.ToString() + " ExpectedTotal=" + _Details.ExpectedTotalBrowseRequests.ToString(), _Details);
                }
            }
            return(this._TestState);
        }
        public override UPnPTestStates Run(ICollection otherSubTests, CdsSubTestArgument arg)
        {
            this._TestState = UPnPTestStates.Running;

            CpContentDirectory CDS = this.GetCDS(arg._Device);
            _Details = new CdsResult_GetSystemUpdateID();

            uint updateID = 0;
            try
            {
                if (CDS != null)
                {
                    DateTime start = System.DateTime.Now;
                    CDS.Sync_GetSystemUpdateID(out updateID);
                    this.LogResponseTime(start, _Details, arg);
                }
            }
            catch (UPnPInvokeException ie)
            {
                arg.TestGroup.AddResult(this._Name + " test failed because of an invocation error: " + ie.Message);
                return UPnPTestStates.Failed;
            }

            arg._TestGroupState.SystemUpdateID = updateID;

            arg.TestGroup.AddResult(this._Name + " test passed. Returned=\"" + updateID.ToString() + "\".");
            this._TestState = UPnPTestStates.Pass;
            return this._TestState;
        }
        public static CdsBrowseSearchResults CheckMetadata(IUPnPMedia checkAgainstThis, CpContentDirectory cds, CdsSubTest test, CdsSubTestArgument arg, CdsResult_BrowseAll details)
        {
            //
            // Save a reference to the media object with the most filterable properties
            int numProperties = 0;
            if (details.MostMetadata != null)
            {
                numProperties = details.MostMetadata.Properties.Count;

                if (details.MostMetadata.DescNodes.Count > 0)
                {
                    numProperties ++;
                }
            }

            int checkValue = 0;

            if (checkAgainstThis.ID != "0")
            {
                if (checkAgainstThis.Resources.Length > 0)
                {
                    checkValue = checkAgainstThis.Properties.Count;
                    if (checkAgainstThis.DescNodes.Count > 0)
                    {
                        checkValue++;
                    }
                }
            }

            if (checkValue > numProperties)
            {
                details.MostMetadata = checkAgainstThis;
            }

            // do a browsemetadata on the media object and determine if the metadata matche.

            BrowseInput input = new BrowseInput();
            input.ObjectID = checkAgainstThis.ID;
            input.BrowseFlag = CpContentDirectory.Enum_A_ARG_TYPE_BrowseFlag.BROWSEMETADATA;
            input.Filter = "*";
            input.StartingIndex = 0;
            input.RequestedCount = 0;
            input.SortCriteria = "";
            IUPnPMedia metadata = null;

            CdsBrowseSearchResults results = Browse(input, test, arg, cds, details);

            test.SetExpectedTestingTime ((details.ExpectedTotalBrowseRequests) * 30);
            arg.ActiveTests.UpdateTimeAndProgress( (details.TotalBrowseRequests) * 30);

            if (results.WorstError <= UPnPTestStates.Warn)
            {
                if (results.NumberReturned != 1)
                {
                    results.SetError(UPnPTestStates.Warn);
                    string msg = "\"" + test.Name + "\": " + input.PrintBrowseParams() + " returned NumberReturned=" +results.NumberReturned+ " when it should logically be 1. This output parameter is not really useful for BrowseMetadata so this logic error does not prevent towards certification, but it should be fixed.";
                    arg._TestGroup.AddEvent(LogImportance.Low, test.Name, msg);
                }

                if (results.TotalMatches != 1)
                {
                    results.SetError(UPnPTestStates.Warn);
                    string msg = "\"" + test.Name + "\": " + input.PrintBrowseParams() + " returned TotalMatches=" +results.TotalMatches+ " when it should logically be 1. This output parameter is not really useful BrowseMetadata so this logic error does not prevent towards certification, but it should be fixed.";
                    arg._TestGroup.AddEvent(LogImportance.Low, test.Name, msg);
                }

                if (results.MediaObjects != null)
                {
                    if (results.MediaObjects.Count == 1)
                    {
                        metadata = results.MediaObjects[0] as IUPnPMedia;

                        if (metadata == null)
                        {
                            throw new TestException(test.Name + " has a TEST LOGIC ERROR. Browse returned without errors but the object's metadata is not stored in an IUPnPMedia object. The offending type is " + results.MediaObjects[0].GetType().ToString(), results.MediaObjects[0]);
                        }

                        if (metadata.ID != input.ObjectID)
                        {
                            results.SetError(UPnPTestStates.Failed);
                            string msg = "\"" + test.Name + "\": " + input.PrintBrowseParams() + " returned a DIDL-Lite media object with ID=\"" +metadata.ID+ "\" when it should be \"" +input.ObjectID+"\" as indicated by the input parameter.";
                            arg._TestGroup.AddEvent(LogImportance.Critical, test.Name, msg);
                        }

                        if (metadata.ParentID != checkAgainstThis.ParentID)
                        {
                            results.SetError(UPnPTestStates.Failed);
                            string msg = "\"" + test.Name + "\": " + input.PrintBrowseParams() + " returned a DIDL-Lite media object with parentID=\"" +metadata.ParentID+ "\" when it should be \"" +checkAgainstThis.ParentID+ "\".";
                            arg._TestGroup.AddEvent(LogImportance.Critical, test.Name, msg);
                        }

                        string original;
                        string received;

                        try
                        {
                            original = checkAgainstThis.ToDidl();
                            received = metadata.ToDidl();
                        }
                        catch
                        {
                            results.SetError(UPnPTestStates.Failed);
                            string msg = "\"" + test.Name + "\": " + input.PrintBrowseParams() + " encountered errors with the DIDL-Lite.";
                            arg._TestGroup.AddEvent(LogImportance.Critical, test.Name, msg);
                            return results;
                        }

                        if (string.Compare(original, received) == 0)
                        {
                            //string msg = "\"" + test.Name + "\": " + input.PrintBrowseParams() + " successfully returned a DIDL-Lite media object that succesfully matches with previously seen metadata.";
                            //arg._TestGroup.AddEvent(LogImportance.Remark, test.Name, msg);
                        }
                        else
                        {
                            System.Xml.XmlDocument doc1 = new XmlDocument();
                            XmlDocument doc2 = new XmlDocument();
                            doc1.LoadXml(original);
                            doc2.LoadXml(received);

                            bool isMatch = true;
                            foreach (XmlElement el1 in doc1.GetElementsByTagName("*"))
                            {
                                bool foundElement = false;
                                foreach (XmlElement el2 in doc2.GetElementsByTagName("*"))
                                {
                                    if (
                                        (el1.Name != "item") &&
                                        (el1.Name != "container") &&
                                        (el1.OuterXml == el2.OuterXml)
                                        )
                                    {
                                        foundElement = true;
                                        break;
                                    }
                                    else if (
                                        (
                                        (el1.Name == "DIDL-Lite") ||
                                        (el1.Name == "item") ||
                                        (el1.Name == "container")
                                        ) &&
                                        (el1.Name == el2.Name)
                                        )
                                    {
                                        foundElement = true;
                                        break;
                                    }
                                }

                                if (foundElement == false)
                                {
                                    isMatch = false;
                                    break;
                                }
                            }

                            if (isMatch==false)
                            {
                                results.SetError(UPnPTestStates.Failed);
                                string msg = "\"" + test.Name + "\": " + input.PrintBrowseParams() + " returned a DIDL-Lite media object that failed to match with previously seen metadata.";
                                arg._TestGroup.AddEvent(LogImportance.Critical, test.Name, msg);
                                arg._TestGroup.AddEvent(LogImportance.Critical, test.Name, test.Name + ": Original=\""+original+"\" Received=\""+received+"\"");
                            }
                        }
                    }
                    else
                    {
                        results.SetError(UPnPTestStates.Failed);
                        string msg = "\"" + test.Name + "\": " + input.PrintBrowseParams() + " did not yield exactly one CDS-compliant media object in its result. Instantiated a total of " +results.MediaObjects.Count+ " media objects.";
                        arg._TestGroup.AddEvent(LogImportance.Critical, test.Name, msg);
                    }
                }
                else
                {
                    throw new TestException(test.Name + " has a TEST LOGIC ERROR. Browse returned without errors but no media objects were instantiated.", null);
                }
            }

            return results;
        }
        public override UPnPTestStates Run(ICollection otherSubTests, CdsSubTestArgument arg)
        {
            CpContentDirectory CDS = this.GetCDS(arg._Device);
            _Details = new CdsResult_BrowseRange();
            this._TestState = UPnPTestStates.Running;

            // get the results from the BrowseAll test
            CdsResult_BrowseAll PRE = null;
            try
            {
                foreach (ISubTest preTest in otherSubTests)
                {
                    if (preTest.Name == this.PRE_BROWSEALL.Name)
                    {
                        PRE = preTest.Details as CdsResult_BrowseAll;
                        break;
                    }
                }

                if (PRE == null)
                {
                    throw new TestException(this._Name + " requires that the \"" + this.PRE_BROWSEALL.Name + "\" test be run as a prerequisite. The results from that test cannot be obtained.", otherSubTests);
                }
            }
            catch (Exception e)
            {
                throw new TestException(this._Name + " requires that the \"" + this.PRE_BROWSEALL.Name + "\" test be run before. An error occurred when attempting to obtain the results of a prerequisite.", otherSubTests, e);
            }
            _Details.BrowseAllResults = PRE;

            if (PRE.LargestContainer == null)
            {
                throw new TestException(this.PRE_BROWSEALL.Name + " failed to find the container with the most child objects. " +this._Name+ " requires this value.", PRE);
            }

            if (PRE.Root == null)
            {
                throw new TestException(this.PRE_BROWSEALL.Name + " failed to find the root container. " +this._Name+ " requires this value.", PRE);
            }

            //calculate expected test time
            //int maxC = PRE.LargestContainer.ChildCount + 1;
            //int rootC = PRE.Root.ChildCount + 1;
            //_Details.ExpectedTotalBrowseRequests = (maxC * maxC) + (rootC * rootC);
            _Details.ExpectedTotalBrowseRequests = CalculateExpectedBrowseRequests(PRE.LargestContainer) + CalculateExpectedBrowseRequests(PRE.Root);
            int maxTime = 300 * _Details.ExpectedTotalBrowseRequests;
            this._ExpectedTestingTime = maxTime;
            arg.ActiveTests.UpdateTimeAndProgress(0);

            // test the root container
            arg.TestGroup.AddEvent(LogImportance.Remark, this.Name, "\"" + this.Name + "\" started testing root container.");
            CdsBrowseSearchResults rootResults = TestContainerRanges(PRE.Root, this, arg, CDS, _Details);
            arg.TestGroup.AddEvent(LogImportance.Remark, this.Name, "\"" + this.Name + "\" finished testing root container.");

            UPnPTestStates state = this._TestState;

            if (state < rootResults.WorstError)
            {
                state = rootResults.WorstError;
            }

            //test largest container
            arg.TestGroup.AddEvent(LogImportance.Remark, this.Name, "\"" + this.Name + "\" started testing containerID=\"" + PRE.LargestContainer.ID + "\".");
            CdsBrowseSearchResults cResults = TestContainerRanges(PRE.LargestContainer, this, arg, CDS, _Details);
            arg.TestGroup.AddEvent(LogImportance.Remark, this.Name, "\"" + this.Name + "\" finished testing containerID=\"" + PRE.LargestContainer.ID + "\".");

            if (state < cResults.WorstError)
            {
                state = cResults.WorstError;
            }

            // finish up logging
            this._TestState = state;

            if (this._TestState >= UPnPTestStates.Warn)
            {
                arg._TestGroup.AddEvent(LogImportance.High, this.Name, "\"" + this.Name + "\" expects all Browse requests to succeed. A CDS should not return errors caused by [(StartingIndex + RequestedCount) >= container.ChildCount] because control points cannot assume a particular range. For leniency, the test will pass with warnings for CDS implementations that return an error when (StartingIndex >= container.ChildCount).");
            }

            StringBuilder sb = new StringBuilder();
            sb.AppendFormat("\"{0}\" completed", this.Name);

            if (this._TestState <= UPnPTestStates.Running)
            {
                throw new TestException("\"" +this.Name+ "\" must have a pass/warn/fail result.", this._TestState);
            }

            switch (this._TestState)
            {
                case UPnPTestStates.Pass:
                    sb.Append(" successfully.");
                    break;
                case UPnPTestStates.Warn:
                    sb.Append(" with warnings.");
                    break;
                case UPnPTestStates.Failed:
                    sb.Append(" with a failed result.");
                    break;
            }

            arg._TestGroup.AddResult(sb.ToString());

            if (this._TestState <= UPnPTestStates.Warn)
            {
                if (_Details.TotalBrowseRequests != _Details.ExpectedTotalBrowseRequests)
                {
                    throw new TestException("TotalBrowseRequests="+_Details.TotalBrowseRequests.ToString()+" ExpectedTotal="+_Details.ExpectedTotalBrowseRequests.ToString(), _Details);
                }
            }

            return this._TestState;
        }
        public static CdsBrowseSearchResults GetContainerMetadataAndValidate(string containerID, CpContentDirectory cds, CdsSubTest test, CdsSubTestArgument arg, CdsResult_BrowseAll details, out IUPnPMedia metadata)
        {
            BrowseInput input = new BrowseInput();
            input.ObjectID = containerID;
            input.BrowseFlag = CpContentDirectory.Enum_A_ARG_TYPE_BrowseFlag.BROWSEMETADATA;
            input.Filter = "*";
            input.StartingIndex = 0;
            input.RequestedCount = 0;
            input.SortCriteria = "";
            metadata = null;

            test.SetExpectedTestingTime ((++details.ExpectedTotalBrowseRequests) * 30);
            arg.ActiveTests.UpdateTimeAndProgress( details.TotalBrowseRequests * 30);

            CdsBrowseSearchResults results = Browse(input, test, arg, cds, details);

            test.SetExpectedTestingTime ((details.ExpectedTotalBrowseRequests) * 30);
            arg.ActiveTests.UpdateTimeAndProgress( (details.TotalBrowseRequests) * 30);

            if (results.InvokeError == null)
            {
                if (results.NumberReturned != 1)
                {
                    //results.SetError(UPnPTestStates.Warn);
                    string msg = "\"" + test.Name + "\": " + input.PrintBrowseParams() + " returned NumberReturned=" +results.NumberReturned+ " when it should logically be 1. This output parameter is not really useful for BrowseMetadata so this logic error does not prevent towards certification, but it should be fixed.";
                    //arg._TestGroup.AddEvent(LogImportance.Low, test.Name, msg);
                    results.ResultErrors.Add( new Exception(msg) );
                }

                if (results.TotalMatches != 1)
                {
                    //results.SetError(UPnPTestStates.Warn);
                    string msg = "\"" + test.Name + "\": " + input.PrintBrowseParams() + " returned TotalMatches=" +results.TotalMatches+ " when it should logically be 1. This output parameter is not really useful BrowseMetadata so this logic error does not prevent towards certification, but it should be fixed.";
                    //arg._TestGroup.AddEvent(LogImportance.Low, test.Name, msg);
                    results.ResultErrors.Add( new Exception(msg) );
                }

                if (results.MediaObjects != null)
                {
                    if (results.MediaObjects.Count == 1)
                    {
                        metadata = results.MediaObjects[0] as IUPnPMedia;

                        if (metadata == null)
                        {
                            throw new TestException(test.Name + " has a TEST LOGIC ERROR. Browse returned without errors but the container's metadata is not stored in an IUPnPMedia object. The offending type is " + results.MediaObjects[0].GetType().ToString(), results.MediaObjects[0]);
                        }

                        IMediaContainer imc = metadata as IMediaContainer;

                        //
                        // check metadata
                        //

                        if (imc == null)
                        {
                            //results.SetError(UPnPTestStates.Failed);
                            string msg = "\"" + test.Name + "\": " + input.PrintBrowseParams() + " returned a DIDL-Lite media object but it was not declared with a \"container\" element.";
                            //arg._TestGroup.AddEvent(LogImportance.Critical, test.Name, msg);
                            results.ResultErrors.Add( new Exception(msg) );
                        }
                        else
                        {
                        }

                        if (metadata.ID != containerID)
                        {
                            //results.SetError(UPnPTestStates.Failed);
                            string msg = "\"" + test.Name + "\": " + input.PrintBrowseParams() + " returned a DIDL-Lite media object with ID=\"" +metadata.ID+ "\" when it should be \"" +containerID+"\" as indicated by the input parameter.";
                            //arg._TestGroup.AddEvent(LogImportance.Critical, test.Name, msg);
                            results.ResultErrors.Add( new Exception(msg) );
                        }

                        if (containerID == "0")
                        {
                            if (metadata.ParentID != "-1")
                            {
                                //results.SetError(UPnPTestStates.Failed);
                                string msg = "\"" + test.Name + "\": " + input.PrintBrowseParams() + " returned a DIDL-Lite media object with parentID=\"" +metadata.ID+ "\" when it must be \"-1\" because the container is the root container.";
                                //arg._TestGroup.AddEvent(LogImportance.Critical, test.Name, msg);
                                results.ResultErrors.Add( new Exception(msg) );
                            }

                            // no need to check parentID values for other containers because
                            // they get checked when getting the children for this container.
                        }

                        if (results.WorstError < UPnPTestStates.Failed)
                        {
                            //string msg = "\"" + test.Name + "\": " + input.PrintBrowseParams() + " succeeded.";
                            //arg._TestGroup.AddEvent(LogImportance.Remark, test.Name, msg);
                        }
                    }
                    else
                    {
                        //results.SetError(UPnPTestStates.Failed);
                        //string msg = "\"" + test.Name + "\": " + input.PrintBrowseParams() + " did not yield exactly one CDS-compliant media object in its result. Instantiated a total of " +results.MediaObjects.Count+ " media objects.";
                        //arg._TestGroup.AddEvent(LogImportance.Critical, test.Name, msg);
                    }
                }
                else
                {
                    //throw new TestException(test.Name + " has a TEST LOGIC ERROR. Browse returned without errors but no media objects were instantiated.", null);
                }
            }

            if ((results.InvokeError != null) || (results.ResultErrors.Count > 0))
            {
                StringBuilder msg = new StringBuilder();
                results.SetError(UPnPTestStates.Failed);

                msg.AppendFormat("\"{0}\": {1} did not yield exactly one CDS-compliant media object in its result. Instantiated a total of {2} media objects.", test.Name, input.PrintBrowseParams(), results.MediaObjects.Count);
                msg.AppendFormat("\r\nAdditional Information:");
                if (results.InvokeError != null)
                {
                    msg.AppendFormat("\r\n{0}", results.InvokeError.Message);
                }

                foreach (Exception e in results.ResultErrors)
                {
                    msg.AppendFormat("\r\n{0}", e.Message);
                }

                arg._TestGroup.AddEvent(LogImportance.Critical, test.Name, msg.ToString());
            }

            return results;
        }
        public static CdsBrowseSearchResults CheckMetadata(IUPnPMedia checkAgainstThis, CpContentDirectory cds, CdsSubTest test, CdsSubTestArgument arg, CdsResult_BrowseAll details)
        {
            //
            // Save a reference to the media object with the most filterable properties
            int numProperties = 0;

            if (details.MostMetadata != null)
            {
                numProperties = details.MostMetadata.Properties.Count;

                if (details.MostMetadata.DescNodes.Count > 0)
                {
                    numProperties++;
                }
            }

            int checkValue = 0;

            if (checkAgainstThis.ID != "0")
            {
                if (checkAgainstThis.Resources.Length > 0)
                {
                    checkValue = checkAgainstThis.Properties.Count;
                    if (checkAgainstThis.DescNodes.Count > 0)
                    {
                        checkValue++;
                    }
                }
            }

            if (checkValue > numProperties)
            {
                details.MostMetadata = checkAgainstThis;
            }

            // do a browsemetadata on the media object and determine if the metadata matche.

            BrowseInput input = new BrowseInput();

            input.ObjectID       = checkAgainstThis.ID;
            input.BrowseFlag     = CpContentDirectory.Enum_A_ARG_TYPE_BrowseFlag.BROWSEMETADATA;
            input.Filter         = "*";
            input.StartingIndex  = 0;
            input.RequestedCount = 0;
            input.SortCriteria   = "";
            IUPnPMedia metadata = null;

            CdsBrowseSearchResults results = Browse(input, test, arg, cds, details);

            test.SetExpectedTestingTime((details.ExpectedTotalBrowseRequests) * 30);
            arg.ActiveTests.UpdateTimeAndProgress((details.TotalBrowseRequests) * 30);

            if (results.WorstError <= UPnPTestStates.Warn)
            {
                if (results.NumberReturned != 1)
                {
                    results.SetError(UPnPTestStates.Warn);
                    string msg = "\"" + test.Name + "\": " + input.PrintBrowseParams() + " returned NumberReturned=" + results.NumberReturned + " when it should logically be 1. This output parameter is not really useful for BrowseMetadata so this logic error does not prevent towards certification, but it should be fixed.";
                    arg._TestGroup.AddEvent(LogImportance.Low, test.Name, msg);
                }

                if (results.TotalMatches != 1)
                {
                    results.SetError(UPnPTestStates.Warn);
                    string msg = "\"" + test.Name + "\": " + input.PrintBrowseParams() + " returned TotalMatches=" + results.TotalMatches + " when it should logically be 1. This output parameter is not really useful BrowseMetadata so this logic error does not prevent towards certification, but it should be fixed.";
                    arg._TestGroup.AddEvent(LogImportance.Low, test.Name, msg);
                }

                if (results.MediaObjects != null)
                {
                    if (results.MediaObjects.Count == 1)
                    {
                        metadata = results.MediaObjects[0] as IUPnPMedia;

                        if (metadata == null)
                        {
                            throw new TestException(test.Name + " has a TEST LOGIC ERROR. Browse returned without errors but the object's metadata is not stored in an IUPnPMedia object. The offending type is " + results.MediaObjects[0].GetType().ToString(), results.MediaObjects[0]);
                        }

                        if (metadata.ID != input.ObjectID)
                        {
                            results.SetError(UPnPTestStates.Failed);
                            string msg = "\"" + test.Name + "\": " + input.PrintBrowseParams() + " returned a DIDL-Lite media object with ID=\"" + metadata.ID + "\" when it should be \"" + input.ObjectID + "\" as indicated by the input parameter.";
                            arg._TestGroup.AddEvent(LogImportance.Critical, test.Name, msg);
                        }

                        if (metadata.ParentID != checkAgainstThis.ParentID)
                        {
                            results.SetError(UPnPTestStates.Failed);
                            string msg = "\"" + test.Name + "\": " + input.PrintBrowseParams() + " returned a DIDL-Lite media object with parentID=\"" + metadata.ParentID + "\" when it should be \"" + checkAgainstThis.ParentID + "\".";
                            arg._TestGroup.AddEvent(LogImportance.Critical, test.Name, msg);
                        }

                        string original;
                        string received;

                        try
                        {
                            original = checkAgainstThis.ToDidl();
                            received = metadata.ToDidl();
                        }
                        catch
                        {
                            results.SetError(UPnPTestStates.Failed);
                            string msg = "\"" + test.Name + "\": " + input.PrintBrowseParams() + " encountered errors with the DIDL-Lite.";
                            arg._TestGroup.AddEvent(LogImportance.Critical, test.Name, msg);
                            return(results);
                        }

                        if (string.Compare(original, received) == 0)
                        {
                            //string msg = "\"" + test.Name + "\": " + input.PrintBrowseParams() + " successfully returned a DIDL-Lite media object that succesfully matches with previously seen metadata.";
                            //arg._TestGroup.AddEvent(LogImportance.Remark, test.Name, msg);
                        }
                        else
                        {
                            System.Xml.XmlDocument doc1 = new XmlDocument();
                            XmlDocument            doc2 = new XmlDocument();
                            doc1.LoadXml(original);
                            doc2.LoadXml(received);

                            bool isMatch = true;
                            foreach (XmlElement el1 in doc1.GetElementsByTagName("*"))
                            {
                                bool foundElement = false;
                                foreach (XmlElement el2 in doc2.GetElementsByTagName("*"))
                                {
                                    if (
                                        (el1.Name != "item") &&
                                        (el1.Name != "container") &&
                                        (el1.OuterXml == el2.OuterXml)
                                        )
                                    {
                                        foundElement = true;
                                        break;
                                    }
                                    else if (
                                        (
                                            (el1.Name == "DIDL-Lite") ||
                                            (el1.Name == "item") ||
                                            (el1.Name == "container")
                                        ) &&
                                        (el1.Name == el2.Name)
                                        )
                                    {
                                        foundElement = true;
                                        break;
                                    }
                                }

                                if (foundElement == false)
                                {
                                    isMatch = false;
                                    break;
                                }
                            }

                            if (isMatch == false)
                            {
                                results.SetError(UPnPTestStates.Failed);
                                string msg = "\"" + test.Name + "\": " + input.PrintBrowseParams() + " returned a DIDL-Lite media object that failed to match with previously seen metadata.";
                                arg._TestGroup.AddEvent(LogImportance.Critical, test.Name, msg);
                                arg._TestGroup.AddEvent(LogImportance.Critical, test.Name, test.Name + ": Original=\"" + original + "\" Received=\"" + received + "\"");
                            }
                        }
                    }
                    else
                    {
                        results.SetError(UPnPTestStates.Failed);
                        string msg = "\"" + test.Name + "\": " + input.PrintBrowseParams() + " did not yield exactly one CDS-compliant media object in its result. Instantiated a total of " + results.MediaObjects.Count + " media objects.";
                        arg._TestGroup.AddEvent(LogImportance.Critical, test.Name, msg);
                    }
                }
                else
                {
                    throw new TestException(test.Name + " has a TEST LOGIC ERROR. Browse returned without errors but no media objects were instantiated.", null);
                }
            }

            return(results);
        }
Esempio n. 24
0
 public abstract UPnPTestStates Run(ICollection otherSubTests, CdsSubTestArgument arg);
Esempio n. 25
0
 protected void LogAverageUnitResponseTime(long averageTime, CdsTestResult result, CdsSubTestArgument arg)
 {
     result.AverageUnitResponseTime = averageTime;
     arg._TestGroup.AddEvent(LogImportance.Remark, this._Name, this._Name + " average unit response time: " + averageTime.ToString() + "ms" + result.UnitDescription);
 }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="parent"></param>
        /// <param name="cds"></param>
        /// <param name="test"></param>
        /// <param name="arg"></param>
        /// <param name="details"></param>
        /// <param name="C"></param>
        /// <returns></returns>
        /// <exception cref="TerminateEarly">
        /// </exception>
        public static ArrayList GetContainerChildrenAndValidate(IMediaContainer parent, CpContentDirectory cds, CdsSubTest test, CdsSubTestArgument arg, CdsResult_BrowseAll details, Queue C)
        {
            uint totalExpected = uint.MaxValue;
            uint currentChild = 0;

            ArrayList children = new ArrayList();

            while (currentChild < totalExpected)
            {
                BrowseInput input = new BrowseInput();
                input.ObjectID = parent.ID;
                input.BrowseFlag = CpContentDirectory.Enum_A_ARG_TYPE_BrowseFlag.BROWSEDIRECTCHILDREN;
                input.Filter = "*";
                input.StartingIndex = currentChild;
                input.RequestedCount = 1;
                input.SortCriteria = "";

                string containerID = parent.ID;

                if (currentChild == 0)
                {
                    test.SetExpectedTestingTime ((++details.ExpectedTotalBrowseRequests) * 30);
                    arg.ActiveTests.UpdateTimeAndProgress( details.TotalBrowseRequests * 30);
                }

                CdsBrowseSearchResults results = Browse(input, test, arg, cds, details);

                test.SetExpectedTestingTime ((details.ExpectedTotalBrowseRequests) * 30);
                arg.ActiveTests.UpdateTimeAndProgress( (details.TotalBrowseRequests) * 30);

                if (results.WorstError >= UPnPTestStates.Failed)
                {
                    throw new TerminateEarly("\"" + test.Name + "\" is terminating early because " +input.PrintBrowseParams()+ " returned with an error or had problems with the DIDL-Lite.");
                }
                else
                {
                    if (results.NumberReturned != 1)
                    {
                        if (currentChild != 0)
                        {
                            results.SetError(UPnPTestStates.Failed);
                            arg._TestGroup.AddEvent(LogImportance.Low, test.Name, "\"" + test.Name + "\": " + input.PrintBrowseParams() + " returned NumberReturned=" +results.NumberReturned+ " when it should logically be 1.");
                        }
                    }

                    if (results.TotalMatches != totalExpected)
                    {
                        if (currentChild != 0)
                        {
                            results.SetError(UPnPTestStates.Failed);
                            arg._TestGroup.AddEvent(LogImportance.Critical, test.Name, "\"" + test.Name + "\": " + input.PrintBrowseParams() + " returned TotalMatches=" +results.TotalMatches+ " when it should logically be " +totalExpected+ " as reported in an earlier Browse request. This portion of the test requires that a MediaServer device not be in a state where its content hierarchy will change.");
                        }
                        else
                        {
                            totalExpected = results.TotalMatches;
                            if (totalExpected > 0)
                            {
                                details.ExpectedTotalBrowseRequests += ((int)results.TotalMatches * 2) - 1;
                                test.SetExpectedTestingTime ((details.ExpectedTotalBrowseRequests) * 30);
                                arg.ActiveTests.UpdateTimeAndProgress( details.TotalBrowseRequests * 30);
                            }
                        }
                    }

                    if (results.MediaObjects != null)
                    {
                        if (results.MediaObjects.Count == 1)
                        {
                            IUPnPMedia child = results.MediaObjects[0] as IUPnPMedia;

                            if (child == null)
                            {
                                throw new TestException("\"" + test.Name + "\"" + " has a TEST LOGIC ERROR. Browse returned without errors but the child object's metadata is not stored in an IUPnPMedia object. The offending type is " + results.MediaObjects[0].GetType().ToString(), results.MediaObjects[0]);
                            }

                            // ensure no duplicates in object ID
                            foreach (IUPnPMedia previousChild in details.AllObjects)
                            {
                                if (previousChild.ID == child.ID)
                                {
                                    string msg = "\"" + test.Name + "\": " + input.PrintBrowseParams() + " returned an object with ID=\"" +child.ID+ "\" which conflicts with a previously seen media object in ParentContainerID=\"" +previousChild.ParentID+ "\".";
                                    arg._TestGroup.AddEvent(LogImportance.Critical, test.Name, msg);
                                    throw new TerminateEarly(msg);
                                }
                            }

                            // ensure updateID is the same between BrowseDirectChildren and earlier BrowseMetadata.

                            try
                            {
                                uint previousUpdateID = (uint) parent.Tag;
                                if (results.UpdateID != previousUpdateID)
                                {
                                    string msg = "\"" + test.Name + "\": " + input.PrintBrowseParams() + " returned an UpdateID=" +results.UpdateID+ " whilst an UpdateID=" +previousUpdateID+ " was obtained in a previous call for ContainerID=\"" +parent.ID+ "\" with BrowseMetadata.";
                                    arg._TestGroup.AddEvent(LogImportance.Critical, test.Name, msg);
                                    throw new TerminateEarly(msg);
                                }
                            }
                            catch (TerminateEarly te)
                            {
                                throw te;
                            }
                            catch (Exception e)
                            {
                                throw new TestException(test.Name + " has a TEST LOGIC ERROR. Error comparing UpdateID values", parent, e);
                            }

                            // add the child to lists: C, parent's child list, and Allobjects
                            try
                            {
                                parent.AddObject(child, false);
                            }
                            catch (Exception e)
                            {
                                AddObjectError aoe = new AddObjectError();
                                aoe.Parent = parent;
                                aoe.Child = child;
                                throw new TestException(test.Name + " has a TEST LOGIC ERROR. Browse returned without errors but the child object could not be added to its parent.", aoe, e);
                            }

                            details.AllObjects.Add(child);
                            children.Add(child);
                            if (child.IsContainer)
                            {
                                C.Enqueue(child);
                                details.TotalContainers++;
                            }
                            else
                            {
                                details.TotalItems++;
                            }

                            //
                            // Do a BrowseMetadata and check to see if the XML values are the same.
                            //

                            CdsBrowseSearchResults compareResults = CheckMetadata(child, cds, test, arg, details);

                            if (compareResults.InvokeError != null)
                            {
                                arg._TestGroup.AddEvent(LogImportance.High, test.Name, test.Name + ": Browse(BrowseDirectChildren,StartingIndex="+currentChild+",RequestedCount=0) on ContainerID=["+containerID+"] succeeded with warnings because a BrowseMetadata request was rejected by the CDS.");
                            }
                            else if (compareResults.ResultErrors.Count > 0)
                            {
                                string msg = "\"" + test.Name + "\": " + input.PrintBrowseParams() + " failed because a BrowseMetadata request succeeded but the DIDL-Lite could not be represented in object form. Invalid DIDL-Lite is most likely the cause.";
                                arg._TestGroup.AddEvent(LogImportance.Critical, test.Name, msg);
                                throw new TerminateEarly(msg);
                            }
                            else if (compareResults.WorstError >= UPnPTestStates.Failed)
                            {
                                string msg = "\"" + test.Name + "\": " + input.PrintBrowseParams() + " failed because one or more child object's failed a comparison of results between BrowseDirectChildren and BrowseMetadata or encountered some other critical error in that process.";
                                arg._TestGroup.AddEvent(LogImportance.Critical, test.Name, msg);
                                throw new TerminateEarly(msg);
                            }
                            else
                            {
                                //string msg = "\"" + test.Name + "\": " + input.PrintBrowseParams() + " succeeded.";
                                //arg._TestGroup.AddEvent(LogImportance.Remark, test.Name, msg);
                            }

                            //
                            // Track the metadata properties found so far
                            // as we may use them in Browse SortCriteria
                            //

                            // standard top-level attributes
                            Tags T = Tags.GetInstance();
                            AddTo(details.PropertyNames, "@"+T[_ATTRIB.id]);
                            AddTo(details.PropertyNames, "@"+T[_ATTRIB.parentID]);
                            AddTo(details.PropertyNames, "@"+T[_ATTRIB.restricted]);
                            if (child.IsContainer)
                            {
                                if (child.IsSearchable)
                                {
                                    AddTo(details.PropertyNames, "@"+T[_ATTRIB.searchable]);
                                    AddTo(details.PropertyNames, T[_DIDL.Container]+"@"+T[_ATTRIB.searchable]);
                                }

                                AddTo(details.PropertyNames, T[_DIDL.Container]+"@"+T[_ATTRIB.id]);
                                AddTo(details.PropertyNames, T[_DIDL.Container]+"@"+T[_ATTRIB.parentID]);
                                AddTo(details.PropertyNames, T[_DIDL.Container]+"@"+T[_ATTRIB.restricted]);
                            }
                            else if (child.IsItem)
                            {
                                if (child.IsReference)
                                {
                                    AddTo(details.PropertyNames, "@"+T[_ATTRIB.refID]);
                                    AddTo(details.PropertyNames, T[_DIDL.Item]+"@"+T[_ATTRIB.refID]);
                                }

                                AddTo(details.PropertyNames, T[_DIDL.Item]+"@"+T[_ATTRIB.id]);
                                AddTo(details.PropertyNames, T[_DIDL.Item]+"@"+T[_ATTRIB.parentID]);
                                AddTo(details.PropertyNames, T[_DIDL.Item]+"@"+T[_ATTRIB.restricted]);
                            }

                            // standard metadata
                            IMediaProperties properties = child.MergedProperties;
                            IList propertyNames = properties.PropertyNames;
                            foreach (string propertyName in propertyNames)
                            {
                                if (details.PropertyNames.Contains(propertyName) == false)
                                {
                                    details.PropertyNames.Add(propertyName);

                                    // add attributes if they are not added
                                    IList propertyValues = properties[propertyName];
                                    foreach (ICdsElement val in propertyValues)
                                    {
                                        ICollection attributes = val.ValidAttributes;
                                        foreach (string attribName in attributes)
                                        {
                                            StringBuilder sbpn = new StringBuilder();
                                            sbpn.AppendFormat("{0}@{1}", propertyName, attribName);
                                            string fullAttribName = sbpn.ToString();
                                            AddTo(details.PropertyNames, fullAttribName);
                                        }
                                    }
                                }

                                // resources
                                IList resources = child.MergedResources;
                                foreach (IMediaResource res in resources)
                                {
                                    ICollection attributes = res.ValidAttributes;
                                    foreach (string attribName in attributes)
                                    {
                                        string name1 = "res@"+attribName;
                                        string name2 = "@"+attribName;

                                        AddTo(details.PropertyNames, name1);
                                        AddTo(details.PropertyNames, name2);
                                    }
                                }

                                if (resources.Count > 0)
                                {
                                    AddTo(details.PropertyNames, T[_DIDL.Res]);
                                }
                            }
                        }
                        else
                        {
                            if (results.TotalMatches > 0)
                            {
                                results.SetError(UPnPTestStates.Failed);
                                string msg = "\"" + test.Name + "\": " + input.PrintBrowseParams() + " did not yield exactly one CDS-compliant media object in its result. Instantiated a total of " +results.MediaObjects.Count+ " media objects.";
                                arg._TestGroup.AddEvent(LogImportance.Critical, test.Name, msg);
                                throw new TerminateEarly(msg);
                            }
                        }
                    }
                    else
                    {
                        throw new TestException(test.Name + " has a TEST LOGIC ERROR. Browse returned without errors but no media objects were instantiated.", null);
                    }
                }

                currentChild++;
            }

            return children;
        }
Esempio n. 27
0
        public void CompareResultsAgainstExpected(CdsBrowseSearchResults br, IList expectedResults, ref UPnPTestStates state, CdsSubTestArgument arg, BrowseInput input, bool strictOrder)
        {
            if (br.WorstError >= UPnPTestStates.Failed)
            {
                throw new TerminateEarly("\"" + this.Name + "\" is terminating early because " + input.PrintBrowseParams() + " returned with an error or had problems with the DIDL-Lite.");
            }
            else
            {
                if (br.MediaObjects.Count != expectedResults.Count)
                {
                    throw new TerminateEarly("\"" + this.Name + "\" did a " + input.PrintBrowseParams() + " and it should have returned " + expectedResults.Count + " media objects. DIDL-Lite contained " + br.MediaObjects.Count + " media objects. DIDL-Lite => " + br.Result);
                }

                bool warnResults = false;
                for (int i = 0; i < br.MediaObjects.Count; i++)
                {
                    IUPnPMedia gotThis       = (IUPnPMedia)br.MediaObjects[i];
                    IUPnPMedia expectedMedia = (IUPnPMedia)expectedResults[i];

                    if (gotThis.ID == expectedMedia.ID)
                    {
                        //arg.TestGroup.AddEvent(LogImportance.Remark, this.Name, "\""+this.Name+"\" did a " +input.PrintBrowseParams()+ " and encountered no errors in the results.");
                    }
                    else
                    {
                        bool failed = false;
                        if ((input.SortCriteria == null) || (input.SortCriteria == ""))
                        {
                            failed = true;
                        }
                        else
                        {
                            // Use this sorter to test for value-equality in situations where the expected order didn't match.
                            // We need to do this because two media objects may be value-equivalent according to a sorting
                            // algorithm, in which case there's no way to really distinguish what order they should be in.
                            IMediaSorter sorter2 = new MediaSorter(false, input.SortCriteria);

                            int cmp = sorter2.Compare(gotThis, expectedMedia);
                            if (cmp != 0)
                            {
                                arg.TestGroup.AddEvent(LogImportance.Medium, this.Name, "\"" + this.Name + "\" found media object ID=\"" + gotThis.ID + "\" when it expected to find \"" + expectedMedia.ID + "\" and they are not equal in their sorted order.");
                                warnResults = true;
                            }
                            else
                            {
                                if (strictOrder == false)
                                {
                                    arg.TestGroup.AddEvent(LogImportance.Low, this.Name, "\"" + this.Name + "\" found media object ID=\"" + gotThis.ID + "\" when it expected to find \"" + expectedMedia.ID + "\" but since they are effectively value-equivalent, the ordering is OK.");
                                }
                                else
                                {
                                    failed = true;
                                }
                            }
                        }

                        if (failed)
                        {
                            StringBuilder msg = new StringBuilder();
                            msg.AppendFormat("\"{0}\" did a {1} and the order of object ID's in the result conflicts with previous browse requests.");
                            msg.AppendFormat("\r\n\r\nReceived objects in order by ID: ");
                            int z = 0;
                            foreach (IUPnPMedia em in br.MediaObjects)
                            {
                                if (z > 0)
                                {
                                    msg.Append(",");
                                }
                                msg.AppendFormat("\"{0}\"", em.ID);
                                z++;
                            }
                            msg.Append("\r\n\r\nThe expected order by ID is: ");
                            z = 0;
                            foreach (IUPnPMedia em in expectedResults)
                            {
                                if (z > 0)
                                {
                                    msg.Append(",");
                                }
                                msg.AppendFormat("\"{0}\"", em.ID);
                                z++;
                            }
                            msg.AppendFormat(".\r\n\r\nDIDL-Lite ==> {0}", br.Result);
                            throw new TerminateEarly(msg.ToString());
                        }
                    }
                }

                if (warnResults == false)
                {
                    arg.TestGroup.AddEvent(LogImportance.Remark, this.Name, "\"" + this.Name + "\" did a " + input.PrintBrowseParams() + " and encountered no errors or warnings in the results.");
                }
                else
                {
                    StringBuilder msg = new StringBuilder();
                    msg.AppendFormat("WARNING: \"{0}\" did a {1} and \r\nreceived results in the following order by ID: ", this.Name, input.PrintBrowseParams());
                    int z = 0;
                    foreach (IUPnPMedia em in br.MediaObjects)
                    {
                        if (z > 0)
                        {
                            msg.Append(",");
                        }
                        msg.AppendFormat("\"{0}\"", em.ID);
                        z++;
                    }
                    msg.Append("\r\n\r\nThe expected order by ID is: ");
                    z = 0;
                    foreach (IUPnPMedia em in expectedResults)
                    {
                        if (z > 0)
                        {
                            msg.Append(",");
                        }
                        msg.AppendFormat("\"{0}\"", em.ID);
                        z++;
                    }
                    msg.AppendFormat(".\r\n\r\nDIDL-Lite ==> {0}", br.Result);
                    // warn
                    state = UPnPTestStates.Warn;
                    arg._TestGroup.AddEvent(LogImportance.Medium, this.Name, msg.ToString());
                }
            }
        }
        public override UPnPTestStates Run(ICollection otherSubTests, CdsSubTestArgument arg)
        {
            CpContentDirectory CDS = this.GetCDS(arg._Device);
            _Details = new CdsResult_BrowseSortCriteria();
            this._TestState = UPnPTestStates.Running;
            arg._TestGroup.AddEvent(LogImportance.Remark, this.Name, "\""+this.Name + "\" started.");

            // get the results from the prerequisite tests
            CdsResult_BrowseAll BROWSE_RESULTS = null;
            CdsResult_GetSortCapabilities SORTCAPS = null;
            try
            {
                foreach (ISubTest preTest in otherSubTests)
                {
                    if (preTest.Name == this.PRE_BROWSEALL.Name)
                    {
                        BROWSE_RESULTS = preTest.Details as CdsResult_BrowseAll;
                    }
                    else if (preTest.Name == this.PRE_SORTCAPS.Name)
                    {
                        SORTCAPS = preTest.Details as CdsResult_GetSortCapabilities;
                    }
                }

                if (BROWSE_RESULTS == null)
                {
                    throw new TestException(this._Name + " requires that the \"" + this.PRE_BROWSEALL.Name + "\" test be run as a prerequisite. The results from that test cannot be obtained.", otherSubTests);
                }

                if (SORTCAPS == null)
                {
                    throw new TestException(this._Name + " requires that the \"" + this.PRE_SORTCAPS.Name + "\" test be run as a prerequisite. The results from that test cannot be obtained.", otherSubTests);
                }
            }
            catch (Exception e)
            {
                throw new TestException(this._Name + " requires that the \"" + this.PRE_BROWSEALL.Name + "\" and \"" + this.PRE_SORTCAPS+ "\" tests be run before. An error occurred when attempting to obtain the results of those prerequisites.", otherSubTests, e);
            }
            _Details.BrowseAllResults = BROWSE_RESULTS;
            _Details.SortCapsResults = SORTCAPS;

            UPnPTestStates state = this._TestState;

            if (BROWSE_RESULTS.LargestContainer == null)
            {
                throw new TestException(this.PRE_BROWSEALL.Name + " failed to find the container with the most child objects. " +this._Name+ " requires this value.", BROWSE_RESULTS);
            }

            MediaContainer MC = BROWSE_RESULTS.LargestContainer as MediaContainer;
            if (MC == null)
            {
                throw new TestException(this.PRE_BROWSEALL.Name + " has the largest container as type \"" +BROWSE_RESULTS.LargestContainer.GetType().ToString() +"\" when \"" +this.Name+ "\" requires \"" +typeof(MediaContainer).ToString()+ "\".", BROWSE_RESULTS);
            }

            ArrayList sortFields = new ArrayList();
            if (SORTCAPS.SortCapabilities == "")
            {
                //arg.TestGroup.AddEvent(LogImportance.Remark, this.Name, "\""+this.Name+"\" has no sorting capabilities.");
            }
            else if (SORTCAPS.SortCapabilities == "*")
            {
                sortFields = (ArrayList) BROWSE_RESULTS.PropertyNames.Clone();
            }
            else
            {
                sortFields.AddRange ( GetSortFields(SORTCAPS.SortCapabilities) );
            }

            _Details.ExpectedTotalBrowseRequests = 0;
            _Details.SortFields = sortFields;
            int fieldCount = sortFields.Count;
            IList childList = BROWSE_RESULTS.LargestContainer.CompleteList;
            _Details.ExpectedTotalBrowseRequests = 0;//fieldCount * fieldCount * fieldCount;
            uint inc = (uint) (childList.Count / 3);
            int firstInc = (fieldCount / 3);
            if (firstInc == 0)
            {
                firstInc = 1;
            }
            for (int numFields = 0; numFields < fieldCount; numFields++)
            {
                for (int first = 0; first < fieldCount; first+=firstInc)
                {
                    //for (uint i=0; i < childList.Count; i+=inc)
                    {
                        _Details.ExpectedTotalBrowseRequests++;
                    }
                }
            }
            // add 1 for an unsorted browse
            _Details.ExpectedTotalBrowseRequests++;
            //multiply by 2 because we have 2 rounds to check for consistency in ordered results
            _Details.ExpectedTotalBrowseRequests *= 2;

            //calculate time
            this._ExpectedTestingTime = _Details.ExpectedTotalBrowseRequests * 900;
            arg.ActiveTests.UpdateTimeAndProgress(0);

            if (state <= UPnPTestStates.Running)
            {
                state = UPnPTestStates.Pass;
                try
                {
                    ArrayList round2 = new ArrayList();

                    //perform the standard unsorted browse
                    BrowseInput input = new BrowseInput();
                    input.BrowseFlag = CpContentDirectory.Enum_A_ARG_TYPE_BrowseFlag.BROWSEDIRECTCHILDREN;
                    input.StartingIndex = 0;
                    input.ObjectID = MC.ID;
                    input.RequestedCount = 0;
                    input.Filter = "*";
                    input.SortCriteria = "";

                    CdsBrowseSearchResults br = Browse(input, this, arg, CDS, _Details);
                    Round2 r2 = new Round2();
                    r2.Input = (BrowseInput) input.Clone();
                    r2.PreviousResult = br;
                    round2.Add(r2);

                    for (int numFields = 0; numFields < fieldCount; numFields++)
                    {
                        for (int first = 0; first < fieldCount; first+=firstInc)
                        {

                            ArrayList sortSettings = GetSortSettings(sortFields, first, first);
                            input.SortCriteria = GetSortCriteriaString(sortSettings, numFields+first);
                            arg.ActiveTests.UpdateTimeAndProgress(_Details.TotalBrowseRequests * 900);

                            uint ignored;

                            //use this sorter for to determine the expected order of the media objects
                            IMediaSorter sorter = new MediaSorter(true, input.SortCriteria);
                            IList expectedSorted = MC.BrowseSorted(0, 0, sorter, out ignored);

                            br = Browse(input, this, arg, CDS, _Details);
                            arg.ActiveTests.UpdateTimeAndProgress(_Details.TotalBrowseRequests * 900);

                            this.CompareResultsAgainstExpected(br, expectedSorted, ref state, arg, input, false);

                            r2 = new Round2();
                            r2.Input = (BrowseInput) input.Clone();
                            r2.PreviousResult = br;
                            round2.Add(r2);
                        }
                    }

                    //do round2 - check for consistency in results
                    foreach (Round2 r in round2)
                    {
                        br = Browse(r.Input, this, arg, CDS, _Details);
                        arg.ActiveTests.UpdateTimeAndProgress(_Details.TotalBrowseRequests * 900);
                        this.CompareResultsAgainstExpected(br, r.PreviousResult.MediaObjects, ref state, arg, r.Input, true);
                    }
                }
                catch (TerminateEarly te)
                {
                    string reason = "\"" +this.Name+ "\" terminating early. Reason => " + te.Message;
                    arg._TestGroup.AddEvent(LogImportance.Critical, this.Name, reason);

                    state = UPnPTestStates.Failed;
                }
            }

            // finish up logging
            this._TestState = state;

            StringBuilder sb = new StringBuilder();
            sb.AppendFormat("\"{0}\" completed", this.Name);

            if (this._TestState <= UPnPTestStates.Running)
            {
                throw new TestException("\"" +this.Name+ "\" must have a pass/warn/fail result.", this._TestState);
            }

            switch (this._TestState)
            {
                case UPnPTestStates.Pass:
                    sb.Append(" successfully.");
                    break;
                case UPnPTestStates.Warn:
                    sb.Append(" with warnings.");
                    break;
                case UPnPTestStates.Failed:
                    sb.Append(" with a failed result.");
                    break;
            }

            arg._TestGroup.AddResult(sb.ToString());

            if (this._TestState <= UPnPTestStates.Warn)
            {
                if (_Details.TotalBrowseRequests != _Details.ExpectedTotalBrowseRequests)
                {
                    throw new TestException("TotalBrowseRequests="+_Details.TotalBrowseRequests.ToString()+" ExpectedTotal="+_Details.ExpectedTotalBrowseRequests.ToString(), _Details);
                }
            }

            arg._TestGroup.AddEvent(LogImportance.Remark, this.Name, sb.ToString());

            return this._TestState;
        }
        /// <summary>
        /// Tests filters for metadata.
        /// </summary>
        /// <param name="testThis"></param>
        /// <param name="test"></param>
        /// <param name="arg"></param>
        /// <param name="cds"></param>
        /// <param name="stats"></param>
        /// <returns></returns>
        public static CdsBrowseSearchResults TestFiltersBrowseMetadata(IUPnPMedia testThis, CpContentDirectory.Enum_A_ARG_TYPE_BrowseFlag browseFlag, Cds_BrowseFilter test, CdsSubTestArgument arg, CpContentDirectory cds, CdsResult_BrowseFilter stats)
        {
            CdsBrowseSearchResults r = new CdsBrowseSearchResults();

            try
            {
                BrowseInput input = new BrowseInput();
                input.BrowseFlag = browseFlag;
                if (input.BrowseFlag == CpContentDirectory.Enum_A_ARG_TYPE_BrowseFlag.BROWSEMETADATA)
                {
                    input.ObjectID = testThis.ID;
                }
                else
                {
                    input.ObjectID = testThis.ParentID;
                }
                input.SortCriteria = "";

                input.StartingIndex = 0;
                input.RequestedCount = 0;

                //assume the test will pass, but worsen the result when we find errors
                r.SetError(UPnPTestStates.Pass);

                ArrayList propNames = new ArrayList((ICollection)testThis.Properties.PropertyNames);

                // add property names related to resources
                propNames.Add(T[_DIDL.Res]);
                foreach (string str in MediaResource.GetPossibleAttributes())
                {
                    propNames.Add(T[_DIDL.Res] + "@" + str);
                    propNames.Add("@" + str);
                }
                propNames.Add(T[_DIDL.Desc]);

                if (propNames.Count != stats.NumberOfProperties)
                {
                    throw new TestException("Number of calculated metadata properties (" + propNames.Count + ") doesn't match number of actual metadata properties (" + propNames.Count + ") for testing.", stats);
                }

                test._Details.Filters = propNames;

                int inc = propNames.Count / 4;
                if (inc == 0)
                {
                    inc = 1;
                }

                for (int numProps = 0; numProps < propNames.Count; numProps++)
                {
                    for (int iProp = 0; iProp < propNames.Count; iProp += inc)
                    {
                        IList filterSettings = GetFilterSettings(propNames, numProps, iProp, iProp);

                        input.Filter = GetCSVString(filterSettings);

                        CdsBrowseSearchResults br;

                        arg.ActiveTests.UpdateTimeAndProgress(90 * stats.TotalBrowseRequests);

                        br = Cds_BrowseAll.Browse(input, test, arg, cds, stats);

                        if (br.WorstError >= UPnPTestStates.Failed)
                        {
                            StringBuilder teMsg = new StringBuilder();

                            teMsg.AppendFormat("\"{0}\" is terminating early because {1} returned with an error or had problems with the DIDL-Lite.", test.Name, input.PrintBrowseParams());
                            if (br.Result != "")
                            {
                                teMsg.AppendFormat(" Returned DIDL=\"{0}\".", br.Result);
                            }
                            throw new TerminateEarly(teMsg.ToString());
                        }
                        //							if (br.InvokeError != null)
                        //							{
                        //								throw new TerminateEarly("\"" + test.Name + "\" is terminating early because " +input.PrintBrowseParams()+ " returned with an error" + br.InvokeError.Message, br.InvokeError);
                        //							}

                        if (input.BrowseFlag == CpContentDirectory.Enum_A_ARG_TYPE_BrowseFlag.BROWSEMETADATA)
                        {
                            if (br.MediaObjects.Count != 1)
                            {
                                throw new TerminateEarly("\"" + test.Name + "\" is terminating early because " + input.PrintBrowseParams() + " did not return with exactly one media object in its DIDL-Lite response. DIDL-Lite => " + br.Result);
                            }

                            IUPnPMedia mo = (IUPnPMedia)br.MediaObjects[0];

                            CheckReturnedMetadata(mo, testThis, input, filterSettings, br, test);
                            arg.TestGroup.AddEvent(LogImportance.Remark, test.Name, "\"" + test.Name + "\" did a " + input.PrintBrowseParams() + " and encountered no errors in the results.");
                        }
                        else
                        {
                            IList childList = testThis.Parent.CompleteList;

                            foreach (IUPnPMedia gotChild in br.MediaObjects)
                            {

                                IUPnPMedia testAgainstChild = null;
                                foreach (IUPnPMedia child in childList)
                                {
                                    if (child.ID == gotChild.ID)
                                    {
                                        testAgainstChild = child;
                                        break;
                                    }
                                }
                                if (testAgainstChild == null)
                                {
                                    throw new TerminateEarly("\"" + test.Name + "\" is terminating early because " + input.PrintBrowseParams() + " returned media object with ID=\"" + gotChild.ID + "\", which was not a child object of containerID=\"" + input.ObjectID + "\" during a prerequisite test.");
                                }
                                CheckReturnedMetadata(gotChild, testAgainstChild, input, filterSettings, br, test);
                                arg.TestGroup.AddEvent(LogImportance.Remark, test.Name, "\"" + test.Name + "\" did a " + input.PrintBrowseParams() + " and encountered no errors in the results.");
                            }
                        }
                    }
                }

            }
            catch (TerminateEarly te)
            {
                string reason = "\"" + test.Name + "\" terminating early. Reason => " + te.Message;
                arg._TestGroup.AddEvent(LogImportance.Critical, test.Name, reason);

                r.SetError(UPnPTestStates.Failed);
                return r;
            }

            if (r.WorstError > UPnPTestStates.Warn)
            {
                throw new TestException("\"" + test.Name + "\" should not reach this code if the result is worse than " + UPnPTestStates.Warn.ToString() + ".", null);
            }

            return r;
        }
        public override UPnPTestStates Run(ICollection otherSubTests, CdsSubTestArgument arg)
        {
            CpContentDirectory CDS = this.GetCDS(arg._Device);

            _Details        = new CdsResult_BrowseFilter();
            this._TestState = UPnPTestStates.Running;
            arg._TestGroup.AddEvent(LogImportance.Remark, this.Name, "\"" + this.Name + "\" started.");

            // get the results from the BrowseAll test
            CdsResult_BrowseAll PRE = null;

            try
            {
                foreach (ISubTest preTest in otherSubTests)
                {
                    if (preTest.Name == this.PRE_BROWSEALL.Name)
                    {
                        PRE = preTest.Details as CdsResult_BrowseAll;
                        break;
                    }
                }

                if (PRE == null)
                {
                    throw new TestException(this._Name + " requires that the \"" + this.PRE_BROWSEALL.Name + "\" test be run as a prerequisite. The results from that test cannot be obtained.", otherSubTests);
                }
            }
            catch (Exception e)
            {
                throw new TestException(this._Name + " requires that the \"" + this.PRE_BROWSEALL.Name + "\" test be run before. An error occurred when attempting to obtain the results of a prerequisite.", otherSubTests, e);
            }
            _Details.BrowseAllResults = PRE;

            if (PRE.MostMetadata == null)
            {
                throw new TestException(this.PRE_BROWSEALL.Name + " failed to find a media object with the most metadata. " + this._Name + " requires this value.", PRE);
            }

            if (PRE.MostMetadata.Properties.Count != PRE.MostMetadata.Properties.PropertyNames.Count)
            {
                throw new TestException(this.Name + " has conflicting reports for the number of metadata properties. " + PRE.MostMetadata.Properties.Count + "/" + PRE.MostMetadata.Properties.PropertyNames.Count, PRE.MostMetadata.Properties);
            }

            IUPnPMedia MM = PRE.MostMetadata;

            if (MM == null)
            {
                string skippedMsg = "\"" + this.Name + "\" skipped because the tested content hierarchy does not have a media object with at least one resource and has an ID!=\"0\"";
                arg.TestGroup.AddEvent(LogImportance.Critical, this.Name, skippedMsg);
                arg.TestGroup.AddResult(skippedMsg);
                return(UPnPTestStates.Ready);
            }

            IMediaContainer MC = PRE.MostMetadata.Parent;

            if (MC == null)
            {
                throw new TestException(this.Name + " has MostMetadata.Parent == null", PRE.MostMetadata);
            }

            int numProps    = MM.Properties.Count;
            int numChildren = MC.ChildCount;

            // we browse for "res" and each possible res@attribute
            numProps += (2 * MediaResource.GetPossibleAttributes().Count) + 2;

            _Details.NumberOfProperties          = numProps;
            _Details.ExpectedTotalBrowseRequests = 0;
            int inc = numProps / 4;

            if (inc == 0)
            {
                inc = 1;
            }
            for (int nProps = 0; nProps < numProps; nProps++)
            {
                for (int iProp = 0; iProp < numProps; iProp += inc)
                {
                    _Details.ExpectedTotalBrowseRequests++;
                }
            }
            _Details.ExpectedTotalBrowseRequests *= 2;
            int maxTime = 90 * _Details.ExpectedTotalBrowseRequests;

            this._ExpectedTestingTime = maxTime;

            // browse metadata with various filter settings
            // browsedirectchildren with various filter settings

            UPnPTestStates state = this._TestState;

            CdsBrowseSearchResults test1 = TestFiltersBrowseMetadata(MM, CpContentDirectory.Enum_A_ARG_TYPE_BrowseFlag.BROWSEMETADATA, this, arg, CDS, _Details);

            if (test1.WorstError > state)
            {
                state = test1.WorstError;
            }

            CdsBrowseSearchResults test2 = TestFiltersBrowseMetadata(MM, CpContentDirectory.Enum_A_ARG_TYPE_BrowseFlag.BROWSEDIRECTCHILDREN, this, arg, CDS, _Details);

            if (test2.WorstError > state)
            {
                state = test2.WorstError;
            }

            // finish up logging
            this._TestState = state;

            StringBuilder sb = new StringBuilder();

            sb.AppendFormat("\"{0}\" completed", this.Name);

            if (this._TestState <= UPnPTestStates.Running)
            {
                throw new TestException("\"" + this.Name + "\" must have a pass/warn/fail result.", this._TestState);
            }

            switch (this._TestState)
            {
            case UPnPTestStates.Pass:
                sb.Append(" successfully.");
                break;

            case UPnPTestStates.Warn:
                sb.Append(" with warnings.");
                break;

            case UPnPTestStates.Failed:
                sb.Append(" with a failed result.");
                break;
            }

            arg._TestGroup.AddResult(sb.ToString());

            if (this._TestState <= UPnPTestStates.Warn)
            {
                if (_Details.TotalBrowseRequests != _Details.ExpectedTotalBrowseRequests)
                {
                    throw new TestException("TotalBrowseRequests=" + _Details.TotalBrowseRequests.ToString() + " ExpectedTotal=" + _Details.ExpectedTotalBrowseRequests.ToString(), _Details);
                }
            }

            arg._TestGroup.AddEvent(LogImportance.Remark, this.Name, sb.ToString());

            return(this._TestState);
        }
        public override UPnPTestStates Run(ICollection otherSubTests, CdsSubTestArgument arg)
        {
            CpContentDirectory CDS = this.GetCDS(arg._Device);
            _Details = new CdsResult_BrowseFilter();
            this._TestState = UPnPTestStates.Running;
            arg._TestGroup.AddEvent(LogImportance.Remark, this.Name, "\"" + this.Name + "\" started.");

            // get the results from the BrowseAll test
            CdsResult_BrowseAll PRE = null;
            try
            {
                foreach (ISubTest preTest in otherSubTests)
                {
                    if (preTest.Name == this.PRE_BROWSEALL.Name)
                    {
                        PRE = preTest.Details as CdsResult_BrowseAll;
                        break;
                    }
                }

                if (PRE == null)
                {
                    throw new TestException(this._Name + " requires that the \"" + this.PRE_BROWSEALL.Name + "\" test be run as a prerequisite. The results from that test cannot be obtained.", otherSubTests);
                }
            }
            catch (Exception e)
            {
                throw new TestException(this._Name + " requires that the \"" + this.PRE_BROWSEALL.Name + "\" test be run before. An error occurred when attempting to obtain the results of a prerequisite.", otherSubTests, e);
            }
            _Details.BrowseAllResults = PRE;

            if (PRE.MostMetadata == null)
            {
                throw new TestException(this.PRE_BROWSEALL.Name + " failed to find a media object with the most metadata. " + this._Name + " requires this value.", PRE);
            }

            if (PRE.MostMetadata.Properties.Count != PRE.MostMetadata.Properties.PropertyNames.Count)
            {
                throw new TestException(this.Name + " has conflicting reports for the number of metadata properties. " + PRE.MostMetadata.Properties.Count + "/" + PRE.MostMetadata.Properties.PropertyNames.Count, PRE.MostMetadata.Properties);
            }

            IUPnPMedia MM = PRE.MostMetadata;

            if (MM == null)
            {
                string skippedMsg = "\"" + this.Name + "\" skipped because the tested content hierarchy does not have a media object with at least one resource and has an ID!=\"0\"";
                arg.TestGroup.AddEvent(LogImportance.Critical, this.Name, skippedMsg);
                arg.TestGroup.AddResult(skippedMsg);
                return UPnPTestStates.Ready;
            }

            IMediaContainer MC = PRE.MostMetadata.Parent;

            if (MC == null)
            {
                throw new TestException(this.Name + " has MostMetadata.Parent == null", PRE.MostMetadata);
            }

            int numProps = MM.Properties.Count;
            int numChildren = MC.ChildCount;

            // we browse for "res" and each possible res@attribute
            numProps += (2 * MediaResource.GetPossibleAttributes().Count) + 2;

            _Details.NumberOfProperties = numProps;
            _Details.ExpectedTotalBrowseRequests = 0;
            int inc = numProps / 4;
            if (inc == 0)
            {
                inc = 1;
            }
            for (int nProps = 0; nProps < numProps; nProps++)
            {
                for (int iProp = 0; iProp < numProps; iProp += inc)
                {
                    _Details.ExpectedTotalBrowseRequests++;
                }
            }
            _Details.ExpectedTotalBrowseRequests *= 2;
            int maxTime = 90 * _Details.ExpectedTotalBrowseRequests;
            this._ExpectedTestingTime = maxTime;

            // browse metadata with various filter settings
            // browsedirectchildren with various filter settings

            UPnPTestStates state = this._TestState;

            CdsBrowseSearchResults test1 = TestFiltersBrowseMetadata(MM, CpContentDirectory.Enum_A_ARG_TYPE_BrowseFlag.BROWSEMETADATA, this, arg, CDS, _Details);

            if (test1.WorstError > state)
            {
                state = test1.WorstError;
            }

            CdsBrowseSearchResults test2 = TestFiltersBrowseMetadata(MM, CpContentDirectory.Enum_A_ARG_TYPE_BrowseFlag.BROWSEDIRECTCHILDREN, this, arg, CDS, _Details);

            if (test2.WorstError > state)
            {
                state = test2.WorstError;
            }

            // finish up logging
            this._TestState = state;

            StringBuilder sb = new StringBuilder();
            sb.AppendFormat("\"{0}\" completed", this.Name);

            if (this._TestState <= UPnPTestStates.Running)
            {
                throw new TestException("\"" + this.Name + "\" must have a pass/warn/fail result.", this._TestState);
            }

            switch (this._TestState)
            {
                case UPnPTestStates.Pass:
                    sb.Append(" successfully.");
                    break;
                case UPnPTestStates.Warn:
                    sb.Append(" with warnings.");
                    break;
                case UPnPTestStates.Failed:
                    sb.Append(" with a failed result.");
                    break;
            }

            arg._TestGroup.AddResult(sb.ToString());

            if (this._TestState <= UPnPTestStates.Warn)
            {
                if (_Details.TotalBrowseRequests != _Details.ExpectedTotalBrowseRequests)
                {
                    throw new TestException("TotalBrowseRequests=" + _Details.TotalBrowseRequests.ToString() + " ExpectedTotal=" + _Details.ExpectedTotalBrowseRequests.ToString(), _Details);
                }
            }

            arg._TestGroup.AddEvent(LogImportance.Remark, this.Name, sb.ToString());

            return this._TestState;
        }
        public override UPnPTestStates Run(ICollection otherSubTests, CdsSubTestArgument arg)
        {
            CpContentDirectory CDS = this.GetCDS(arg._Device);

            _Details        = new CdsResult_BrowseRange();
            this._TestState = UPnPTestStates.Running;

            // get the results from the BrowseAll test
            CdsResult_BrowseAll PRE = null;

            try
            {
                foreach (ISubTest preTest in otherSubTests)
                {
                    if (preTest.Name == this.PRE_BROWSEALL.Name)
                    {
                        PRE = preTest.Details as CdsResult_BrowseAll;
                        break;
                    }
                }

                if (PRE == null)
                {
                    throw new TestException(this._Name + " requires that the \"" + this.PRE_BROWSEALL.Name + "\" test be run as a prerequisite. The results from that test cannot be obtained.", otherSubTests);
                }
            }
            catch (Exception e)
            {
                throw new TestException(this._Name + " requires that the \"" + this.PRE_BROWSEALL.Name + "\" test be run before. An error occurred when attempting to obtain the results of a prerequisite.", otherSubTests, e);
            }
            _Details.BrowseAllResults = PRE;

            if (PRE.LargestContainer == null)
            {
                throw new TestException(this.PRE_BROWSEALL.Name + " failed to find the container with the most child objects. " + this._Name + " requires this value.", PRE);
            }

            if (PRE.Root == null)
            {
                throw new TestException(this.PRE_BROWSEALL.Name + " failed to find the root container. " + this._Name + " requires this value.", PRE);
            }

            //calculate expected test time
            //int maxC = PRE.LargestContainer.ChildCount + 1;
            //int rootC = PRE.Root.ChildCount + 1;
            //_Details.ExpectedTotalBrowseRequests = (maxC * maxC) + (rootC * rootC);
            _Details.ExpectedTotalBrowseRequests = CalculateExpectedBrowseRequests(PRE.LargestContainer) + CalculateExpectedBrowseRequests(PRE.Root);
            int maxTime = 300 * _Details.ExpectedTotalBrowseRequests;

            this._ExpectedTestingTime = maxTime;
            arg.ActiveTests.UpdateTimeAndProgress(0);


            // test the root container
            arg.TestGroup.AddEvent(LogImportance.Remark, this.Name, "\"" + this.Name + "\" started testing root container.");
            CdsBrowseSearchResults rootResults = TestContainerRanges(PRE.Root, this, arg, CDS, _Details);

            arg.TestGroup.AddEvent(LogImportance.Remark, this.Name, "\"" + this.Name + "\" finished testing root container.");

            UPnPTestStates state = this._TestState;

            if (state < rootResults.WorstError)
            {
                state = rootResults.WorstError;
            }

            //test largest container
            arg.TestGroup.AddEvent(LogImportance.Remark, this.Name, "\"" + this.Name + "\" started testing containerID=\"" + PRE.LargestContainer.ID + "\".");
            CdsBrowseSearchResults cResults = TestContainerRanges(PRE.LargestContainer, this, arg, CDS, _Details);

            arg.TestGroup.AddEvent(LogImportance.Remark, this.Name, "\"" + this.Name + "\" finished testing containerID=\"" + PRE.LargestContainer.ID + "\".");

            if (state < cResults.WorstError)
            {
                state = cResults.WorstError;
            }


            // finish up logging
            this._TestState = state;

            if (this._TestState >= UPnPTestStates.Warn)
            {
                arg._TestGroup.AddEvent(LogImportance.High, this.Name, "\"" + this.Name + "\" expects all Browse requests to succeed. A CDS should not return errors caused by [(StartingIndex + RequestedCount) >= container.ChildCount] because control points cannot assume a particular range. For leniency, the test will pass with warnings for CDS implementations that return an error when (StartingIndex >= container.ChildCount).");
            }

            StringBuilder sb = new StringBuilder();

            sb.AppendFormat("\"{0}\" completed", this.Name);

            if (this._TestState <= UPnPTestStates.Running)
            {
                throw new TestException("\"" + this.Name + "\" must have a pass/warn/fail result.", this._TestState);
            }

            switch (this._TestState)
            {
            case UPnPTestStates.Pass:
                sb.Append(" successfully.");
                break;

            case UPnPTestStates.Warn:
                sb.Append(" with warnings.");
                break;

            case UPnPTestStates.Failed:
                sb.Append(" with a failed result.");
                break;
            }

            arg._TestGroup.AddResult(sb.ToString());

            if (this._TestState <= UPnPTestStates.Warn)
            {
                if (_Details.TotalBrowseRequests != _Details.ExpectedTotalBrowseRequests)
                {
                    throw new TestException("TotalBrowseRequests=" + _Details.TotalBrowseRequests.ToString() + " ExpectedTotal=" + _Details.ExpectedTotalBrowseRequests.ToString(), _Details);
                }
            }

            return(this._TestState);
        }
        public override UPnPTestStates Run(ICollection otherSubTests, CdsSubTestArgument arg)
        {
            CpContentDirectory CDS = this.GetCDS(arg._Device);

            _Details        = new CdsResult_BrowseFilterRangeSort();
            this._TestState = UPnPTestStates.Running;
            arg._TestGroup.AddEvent(LogImportance.Remark, this.Name, "\"" + this.Name + "\" started.");


            // get the results from the prerequisite tests
            CdsResult_BrowseFilter       FILTER_RESULTS = null;
            CdsResult_BrowseRange        RANGE_RESULTS  = null;
            CdsResult_BrowseSortCriteria SORT_RESULTS   = null;

            try
            {
                foreach (ISubTest preTest in otherSubTests)
                {
                    if (preTest.Name == this.PRE_FILTER.Name)
                    {
                        FILTER_RESULTS = preTest.Details as CdsResult_BrowseFilter;
                    }
                    else if (preTest.Name == this.PRE_RANGE.Name)
                    {
                        RANGE_RESULTS = preTest.Details as CdsResult_BrowseRange;
                    }
                    else if (preTest.Name == this.PRE_SORT.Name)
                    {
                        SORT_RESULTS = preTest.Details as CdsResult_BrowseSortCriteria;
                    }
                }

                if (FILTER_RESULTS == null)
                {
                    throw new TestException(this._Name + " requires that the \"" + this.PRE_FILTER.Name + "\" test be run as a prerequisite. The results from that test cannot be obtained.", otherSubTests);
                }

                if (RANGE_RESULTS == null)
                {
                    throw new TestException(this._Name + " requires that the \"" + this.PRE_RANGE.Name + "\" test be run as a prerequisite. The results from that test cannot be obtained.", otherSubTests);
                }

                if (SORT_RESULTS == null)
                {
                    throw new TestException(this._Name + " requires that the \"" + this.PRE_SORT.Name + "\" test be run as a prerequisite. The results from that test cannot be obtained.", otherSubTests);
                }
            }
            catch (Exception e)
            {
                throw new TestException(this._Name + " requires that the \"" + this.PRE_FILTER.Name + "\" and \"" + this.PRE_RANGE + "\" and \"" + this.PRE_SORT + "\" tests be run before. An error occurred when attempting to obtain the results of those prerequisites.", otherSubTests, e);
            }

            UPnPTestStates      state      = this._TestState;
            CdsResult_BrowseAll BROWSE_ALL = FILTER_RESULTS.BrowseAllResults;

            if (BROWSE_ALL.LargestContainer == null)
            {
                throw new TestException(new Cds_BrowseAll().Name + " failed to find the container with the most child objects. " + this._Name + " requires this value.", BROWSE_ALL);
            }
            if (BROWSE_ALL.MostMetadata == null)
            {
                throw new TestException(new Cds_BrowseAll().Name + " failed to find the media object with the most metadata. " + this._Name + " requires this value.", BROWSE_ALL);
            }
            if (SORT_RESULTS.SortFields == null)
            {
                throw new TestException(new Cds_BrowseAll().Name + " failed to find the sortable fields. " + this._Name + " requires this value.", SORT_RESULTS);
            }

            int max = Math.Max(FILTER_RESULTS.Filters.Count, BROWSE_ALL.LargestContainer.ChildCount);

            max = Math.Max(max, SORT_RESULTS.SortFields.Count);

            this._Details.ExpectedTotalBrowseRequests = max + 1;
            this._Details.TotalBrowseRequests         = 0;
            this._ExpectedTestingTime = this._Details.ExpectedTotalBrowseRequests * 900;
            arg.ActiveTests.UpdateTimeAndProgress(this._Details.TotalBrowseRequests * 900);

            state = UPnPTestStates.Pass;
            for (int i = 0; i <= max; i++)
            {
                ArrayList filterList = new ArrayList();
                for (int j = 0; j < i; j++)
                {
                    if (j < FILTER_RESULTS.Filters.Count)
                    {
                        filterList.Add(FILTER_RESULTS.Filters[j]);
                    }
                    else
                    {
                        break;
                    }
                }
                string filterSettings = Cds_BrowseTest.GetCSVString(filterList);


                uint range = (uint)i;
                if (range > BROWSE_ALL.LargestContainer.ChildCount)
                {
                    range = (uint)BROWSE_ALL.LargestContainer.ChildCount;
                }


                ArrayList sortList = new ArrayList();
                for (int j = 0; j < i; j++)
                {
                    if (j < SORT_RESULTS.SortFields.Count)
                    {
                        sortList.Add(SORT_RESULTS.SortFields[j]);
                    }
                    else
                    {
                        break;
                    }
                }

                BrowseInput input = new BrowseInput();
                input.ObjectID       = BROWSE_ALL.LargestContainer.ID;
                input.BrowseFlag     = CpContentDirectory.Enum_A_ARG_TYPE_BrowseFlag.BROWSEDIRECTCHILDREN;
                input.Filter         = filterSettings;
                input.RequestedCount = range;
                input.SortCriteria   = Cds_BrowseSortCriteria.GetSortCriteriaString(sortList, i);
                input.StartingIndex  = 0;

                this._ExpectedTestingTime = (max) * 900;
                arg.ActiveTests.UpdateTimeAndProgress(this._Details.TotalBrowseRequests * 900);
                CdsBrowseSearchResults br = Cds_BrowseTest.Browse(input, this, arg, CDS, _Details);

                MediaContainer original = (MediaContainer)BROWSE_ALL.LargestContainer;
                uint           ignored;
                IList          expectedResults;

                expectedResults = original.BrowseSorted(0, input.RequestedCount, new MediaSorter(true, input.SortCriteria), out ignored);

                try
                {
                    if (br.WorstError <= UPnPTestStates.Warn)
                    {
                        if (br.MediaObjects.Count != expectedResults.Count)
                        {
                            throw new TerminateEarly(input.PrintBrowseParams() + " returned DIDL-Lite that declared " + br.MediaObjects.Count + " media objects but test expected " + expectedResults.Count.ToString() + " media objects as found in a prerequisite test.");
                        }

                        bool warnOrder = false;
                        for (int ri = 0; ri < br.MediaObjects.Count; ri++)
                        {
                            IUPnPMedia resultObj   = (IUPnPMedia)br.MediaObjects[ri];
                            IUPnPMedia originalObj = (IUPnPMedia)expectedResults[ri];

                            if (resultObj.ID != originalObj.ID)
                            {
                                warnOrder = true;
                            }

                            foreach (string propName in resultObj.Properties.PropertyNames)
                            {
                                if (filterList.Contains(propName) == false)
                                {
                                    if (
                                        (propName != T[_DC.title]) &&
                                        (propName != T[_UPNP.Class])
                                        )
                                    {
                                        StringBuilder msg = new StringBuilder();
                                        msg.AppendFormat("\"" + this.Name + "\" is terminating early because {0} returned DIDL-Lite with \"{1}\" metadata when it should not have done so.", input.PrintBrowseParams(), propName);
                                        throw new TerminateEarly(msg.ToString());
                                    }
                                }
                            }
                        }

                        int expectedCount = i;
                        if ((i == 0) || (i > BROWSE_ALL.LargestContainer.ChildCount))
                        {
                            expectedCount = BROWSE_ALL.LargestContainer.ChildCount;
                        }

                        if (br.MediaObjects.Count != expectedCount)
                        {
                            StringBuilder msg = new StringBuilder();
                            msg.AppendFormat("\"{0}\" did a {1} and the DIDL-Lite result only has {2} media objects when {3} media objects were expected.", this.Name, input.PrintBrowseParams(), br.MediaObjects.Count, expectedCount);
                            msg.AppendFormat(".\r\nDIDL-Lite ==> {0}", br.Result);
                            throw new TerminateEarly(msg.ToString());
                        }

                        if (warnOrder)
                        {
                            /*
                             * ArrayList missingResults = new ArrayList();
                             *
                             * foreach (IUPnPMedia em in expectedResults)
                             * {
                             *      bool found = false;
                             *      foreach (IUPnPMedia fm in br.MediaObjects)
                             *      {
                             *              if (em.ID == fm.ID)
                             *              {
                             *                      found = true;
                             *                      break;
                             *              }
                             *      }
                             *
                             *      if (found == false)
                             *      {
                             *              missingResults.Add(em);
                             *      }
                             * }
                             *
                             * if (missingResults.Count > 0)
                             * {
                             *      state = UPnPTestStates.Failed;
                             *      StringBuilder msg = new StringBuilder();
                             *      msg.AppendFormat("\"{0}\" did a {1} and the result is missing media objects.", this.Name, input.PrintBrowseParams());
                             *      msg.Append("\r\nExpected order of IDs: ");
                             *      int z = 0;
                             *      foreach (IUPnPMedia em in expectedResults)
                             *      {
                             *              if (z > 0)
                             *              {
                             *                      msg.Append(",");
                             *              }
                             *              msg.AppendFormat("\"{0}\"", em.ID);
                             *              z++;
                             *      }
                             *      msg.Append("\r\nDIDL-Lite result's order of IDs: ");
                             *      z = 0;
                             *      foreach (IUPnPMedia em in br.MediaObjects)
                             *      {
                             *              if (z > 0)
                             *              {
                             *                      msg.Append(",");
                             *              }
                             *              msg.AppendFormat("\"{0}\"", em.ID);
                             *              z++;
                             *      }
                             *      msg.AppendFormat(".\r\nDIDL-Lite ==> {0}", br.Result);
                             *      throw new TerminateEarly(msg.ToString());
                             * }
                             * else
                             */
                            {
                                StringBuilder msg = new StringBuilder();
                                msg.AppendFormat("WARNING: \"{0}\" did a {1} and got items in a different order. Target CDS either has an error in its sorting logic, or sorting logic intentionally deviates from test.", this.Name, input.PrintBrowseParams());
                                msg.Append("\r\nExpected order of IDs: ");
                                int z = 0;
                                foreach (IUPnPMedia em in expectedResults)
                                {
                                    if (z > 0)
                                    {
                                        msg.Append(",");
                                    }
                                    msg.AppendFormat("\"{0}\"", em.ID);
                                    z++;
                                }
                                msg.Append("\r\nDIDL-Lite result's order of IDs: ");
                                z = 0;
                                foreach (IUPnPMedia em in br.MediaObjects)
                                {
                                    if (z > 0)
                                    {
                                        msg.Append(",");
                                    }
                                    msg.AppendFormat("\"{0}\"", em.ID);
                                    z++;
                                }
                                msg.AppendFormat(".\r\nDIDL-Lite ==> {0}", br.Result);
                                arg._TestGroup.AddEvent(LogImportance.Medium, this.Name, msg.ToString());
                                state = UPnPTestStates.Warn;
                            }
                        }
                    }
                    else
                    {
                        throw new TerminateEarly("\"" + this.Name + "\" is terminating early because " + input.PrintBrowseParams() + " returned with an error or had problems with the DIDL-Lite.");
                    }
                }
                catch (TerminateEarly te)
                {
                    arg._TestGroup.AddEvent(LogImportance.Critical, this.Name, "\"" + this.Name + "\" terminating early. Reason ==> " + te.Message);
                    state = UPnPTestStates.Failed;
                    break;
                }
            }


            // finish up logging
            this._TestState = state;

            StringBuilder sb = new StringBuilder();

            sb.AppendFormat("\"{0}\" completed", this.Name);

            if (this._TestState <= UPnPTestStates.Running)
            {
                throw new TestException("\"" + this.Name + "\" must have a pass/warn/fail result.", this._TestState);
            }

            switch (this._TestState)
            {
            case UPnPTestStates.Pass:
                sb.Append(" successfully.");
                break;

            case UPnPTestStates.Warn:
                sb.Append(" with warnings.");
                break;

            case UPnPTestStates.Failed:
                sb.Append(" with a failed result.");
                break;
            }

            arg._TestGroup.AddResult(sb.ToString());

            if (this._TestState <= UPnPTestStates.Warn)
            {
                if (_Details.TotalBrowseRequests != _Details.ExpectedTotalBrowseRequests)
                {
                    throw new TestException("TotalBrowseRequests=" + _Details.TotalBrowseRequests.ToString() + " ExpectedTotal=" + _Details.ExpectedTotalBrowseRequests.ToString(), _Details);
                }
            }

            arg._TestGroup.AddEvent(LogImportance.Remark, this.Name, this.Name + " finished.");

            return(this._TestState);
        }
        public static CdsBrowseSearchResults GetContainerMetadataAndValidate(string containerID, CpContentDirectory cds, CdsSubTest test, CdsSubTestArgument arg, CdsResult_BrowseAll details, out IUPnPMedia metadata)
        {
            BrowseInput input = new BrowseInput();

            input.ObjectID       = containerID;
            input.BrowseFlag     = CpContentDirectory.Enum_A_ARG_TYPE_BrowseFlag.BROWSEMETADATA;
            input.Filter         = "*";
            input.StartingIndex  = 0;
            input.RequestedCount = 0;
            input.SortCriteria   = "";
            metadata             = null;

            test.SetExpectedTestingTime((++details.ExpectedTotalBrowseRequests) * 30);
            arg.ActiveTests.UpdateTimeAndProgress(details.TotalBrowseRequests * 30);

            CdsBrowseSearchResults results = Browse(input, test, arg, cds, details);

            test.SetExpectedTestingTime((details.ExpectedTotalBrowseRequests) * 30);
            arg.ActiveTests.UpdateTimeAndProgress((details.TotalBrowseRequests) * 30);

            if (results.InvokeError == null)
            {
                if (results.NumberReturned != 1)
                {
                    //results.SetError(UPnPTestStates.Warn);
                    string msg = "\"" + test.Name + "\": " + input.PrintBrowseParams() + " returned NumberReturned=" + results.NumberReturned + " when it should logically be 1. This output parameter is not really useful for BrowseMetadata so this logic error does not prevent towards certification, but it should be fixed.";
                    //arg._TestGroup.AddEvent(LogImportance.Low, test.Name, msg);
                    results.ResultErrors.Add(new Exception(msg));
                }

                if (results.TotalMatches != 1)
                {
                    //results.SetError(UPnPTestStates.Warn);
                    string msg = "\"" + test.Name + "\": " + input.PrintBrowseParams() + " returned TotalMatches=" + results.TotalMatches + " when it should logically be 1. This output parameter is not really useful BrowseMetadata so this logic error does not prevent towards certification, but it should be fixed.";
                    //arg._TestGroup.AddEvent(LogImportance.Low, test.Name, msg);
                    results.ResultErrors.Add(new Exception(msg));
                }

                if (results.MediaObjects != null)
                {
                    if (results.MediaObjects.Count == 1)
                    {
                        metadata = results.MediaObjects[0] as IUPnPMedia;

                        if (metadata == null)
                        {
                            throw new TestException(test.Name + " has a TEST LOGIC ERROR. Browse returned without errors but the container's metadata is not stored in an IUPnPMedia object. The offending type is " + results.MediaObjects[0].GetType().ToString(), results.MediaObjects[0]);
                        }

                        IMediaContainer imc = metadata as IMediaContainer;

                        //
                        // check metadata
                        //

                        if (imc == null)
                        {
                            //results.SetError(UPnPTestStates.Failed);
                            string msg = "\"" + test.Name + "\": " + input.PrintBrowseParams() + " returned a DIDL-Lite media object but it was not declared with a \"container\" element.";
                            //arg._TestGroup.AddEvent(LogImportance.Critical, test.Name, msg);
                            results.ResultErrors.Add(new Exception(msg));
                        }
                        else
                        {
                        }

                        if (metadata.ID != containerID)
                        {
                            //results.SetError(UPnPTestStates.Failed);
                            string msg = "\"" + test.Name + "\": " + input.PrintBrowseParams() + " returned a DIDL-Lite media object with ID=\"" + metadata.ID + "\" when it should be \"" + containerID + "\" as indicated by the input parameter.";
                            //arg._TestGroup.AddEvent(LogImportance.Critical, test.Name, msg);
                            results.ResultErrors.Add(new Exception(msg));
                        }

                        if (containerID == "0")
                        {
                            if (metadata.ParentID != "-1")
                            {
                                //results.SetError(UPnPTestStates.Failed);
                                string msg = "\"" + test.Name + "\": " + input.PrintBrowseParams() + " returned a DIDL-Lite media object with parentID=\"" + metadata.ID + "\" when it must be \"-1\" because the container is the root container.";
                                //arg._TestGroup.AddEvent(LogImportance.Critical, test.Name, msg);
                                results.ResultErrors.Add(new Exception(msg));
                            }

                            // no need to check parentID values for other containers because
                            // they get checked when getting the children for this container.
                        }

                        if (results.WorstError < UPnPTestStates.Failed)
                        {
                            //string msg = "\"" + test.Name + "\": " + input.PrintBrowseParams() + " succeeded.";
                            //arg._TestGroup.AddEvent(LogImportance.Remark, test.Name, msg);
                        }
                    }
                    else
                    {
                        //results.SetError(UPnPTestStates.Failed);
                        //string msg = "\"" + test.Name + "\": " + input.PrintBrowseParams() + " did not yield exactly one CDS-compliant media object in its result. Instantiated a total of " +results.MediaObjects.Count+ " media objects.";
                        //arg._TestGroup.AddEvent(LogImportance.Critical, test.Name, msg);
                    }
                }
                else
                {
                    //throw new TestException(test.Name + " has a TEST LOGIC ERROR. Browse returned without errors but no media objects were instantiated.", null);
                }
            }

            if ((results.InvokeError != null) || (results.ResultErrors.Count > 0))
            {
                StringBuilder msg = new StringBuilder();
                results.SetError(UPnPTestStates.Failed);

                msg.AppendFormat("\"{0}\": {1} did not yield exactly one CDS-compliant media object in its result. Instantiated a total of {2} media objects.", test.Name, input.PrintBrowseParams(), results.MediaObjects.Count);
                msg.AppendFormat("\r\nAdditional Information:");
                if (results.InvokeError != null)
                {
                    msg.AppendFormat("\r\n{0}", results.InvokeError.Message);
                }

                foreach (Exception e in results.ResultErrors)
                {
                    msg.AppendFormat("\r\n{0}", e.Message);
                }

                arg._TestGroup.AddEvent(LogImportance.Critical, test.Name, msg.ToString());
            }

            return(results);
        }
        /// <summary>
        /// Performs a Browse invocation.
        /// </summary>
        /// <param name="input"></param>
        /// <param name="test"></param>
        /// <param name="arg"></param>
        /// <param name="cds"></param>
        /// <param name="stats"></param>
        /// <returns></returns>
        public static CdsBrowseSearchResults Browse(BrowseInput input, CdsSubTest test, CdsSubTestArgument arg, CpContentDirectory cds, CdsResult_BrowseStats stats)
        {
            CdsBrowseSearchResults results = new CdsBrowseSearchResults();
            results.SetError(UPnPTestStates.Pass);
            results.ResultErrors = new ArrayList();

            arg._TestGroup.AddEvent(LogImportance.Remark, test.Name, "\""+test.Name+"\" about to do " + input.PrintBrowseParams()+ ".");
            try
            {
                cds.Sync_Browse(input.ObjectID, input.BrowseFlag, input.Filter, input.StartingIndex, input.RequestedCount, input.SortCriteria, out results.Result, out results.NumberReturned, out results.TotalMatches, out results.UpdateID);
            }
            catch (UPnPInvokeException error)
            {
                results.InvokeError = error;
            }

            if (results.InvokeError == null)
            {
                arg._TestGroup.AddEvent(LogImportance.Remark, test.Name, "\""+test.Name+"\" completed " + input.PrintBrowseParams()+ " with no errors returned by the device.");
            }
            else
            {
                arg._TestGroup.AddEvent(LogImportance.Remark, test.Name, "\""+test.Name+"\" completed " + input.PrintBrowseParams()+ " with the device returning an error.");
            }

            stats.TotalBrowseRequests++;
            ArrayList branches = null;
            if (results.InvokeError == null)
            {
                try
                {
                    if (results.Result != null)
                    {
                        if (results.Result != "")
                        {
                            bool schemaOK = CheckDidlLiteSchema(results.Result);

                            if (schemaOK)
                            {
                                results.MediaObjects = branches = MediaBuilder.BuildMediaBranches(results.Result, typeof (MediaItem), typeof(MediaContainer), true);

                                if (branches.Count != results.NumberReturned)
                                {
                                    results.ResultErrors.Add (new CdsException(input.PrintBrowseParams() + " has the \"Result\" argument indicating the presence of " +branches.Count+ " media objects but the request returned NumberReturned=" +results.NumberReturned+"."));
                                }

                                if (input.BrowseFlag == CpContentDirectory.Enum_A_ARG_TYPE_BrowseFlag.BROWSEMETADATA)
                                {
                                    if (branches.Count != 1)
                                    {
                                        results.ResultErrors.Add (new CdsException(input.PrintBrowseParams() + " has the \"Result\" argument indicating the presence of " +branches.Count+ " media objects but the request should have only returned 1 media object."));
                                    }
                                }

                                foreach (IUPnPMedia mobj in branches)
                                {
                                    IMediaContainer imc = mobj as IMediaContainer;

                                    if (imc != null)
                                    {
                                        if (imc.CompleteList.Count > 0)
                                        {
                                            StringBuilder offendingList = new StringBuilder();
                                            int offenses = 0;
                                            foreach (IUPnPMedia offending in imc.CompleteList)
                                            {
                                                if (offenses > 0)
                                                {
                                                    offendingList.Append(",");
                                                }
                                                offendingList.AppendFormat("\"{0}\"", offending.ID);
                                                offenses++;
                                            }
                                            results.ResultErrors.Add (new CdsException(input.PrintBrowseParams() + " has the \"Result\" argument with a declared container (ID=\""+imc.ID+"\") element that also includes its immediate children. Illegally declared media objects in the response are: "+offendingList.ToString()));
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                catch (Exception error2)
                {
                    results.ResultErrors.Add (error2);
                    if (results.MediaObjects == null)
                    {
                        results.MediaObjects = new ArrayList();
                    }
                }
            }

            // log any errors
            if ((results.InvokeError != null) || (results.ResultErrors.Count > 0))
            {
                LogErrors(arg._TestGroup, test, input, "Browse", results.InvokeError, results.ResultErrors);
                results.SetError(UPnPTestStates.Failed);
            }

            return results;
        }
Esempio n. 36
0
 public abstract UPnPTestStates Run(ICollection otherSubTests, CdsSubTestArgument arg);
Esempio n. 37
0
        public override UPnPTestStates Run(ICollection otherSubTests, CdsSubTestArgument arg)
        {
            CpContentDirectory CDS = this.GetCDS(arg._Device);

            _Details        = new CdsResult_BrowseSortCriteria();
            this._TestState = UPnPTestStates.Running;
            arg._TestGroup.AddEvent(LogImportance.Remark, this.Name, "\"" + this.Name + "\" started.");

            // get the results from the prerequisite tests
            CdsResult_BrowseAll           BROWSE_RESULTS = null;
            CdsResult_GetSortCapabilities SORTCAPS       = null;

            try
            {
                foreach (ISubTest preTest in otherSubTests)
                {
                    if (preTest.Name == this.PRE_BROWSEALL.Name)
                    {
                        BROWSE_RESULTS = preTest.Details as CdsResult_BrowseAll;
                    }
                    else if (preTest.Name == this.PRE_SORTCAPS.Name)
                    {
                        SORTCAPS = preTest.Details as CdsResult_GetSortCapabilities;
                    }
                }

                if (BROWSE_RESULTS == null)
                {
                    throw new TestException(this._Name + " requires that the \"" + this.PRE_BROWSEALL.Name + "\" test be run as a prerequisite. The results from that test cannot be obtained.", otherSubTests);
                }

                if (SORTCAPS == null)
                {
                    throw new TestException(this._Name + " requires that the \"" + this.PRE_SORTCAPS.Name + "\" test be run as a prerequisite. The results from that test cannot be obtained.", otherSubTests);
                }
            }
            catch (Exception e)
            {
                throw new TestException(this._Name + " requires that the \"" + this.PRE_BROWSEALL.Name + "\" and \"" + this.PRE_SORTCAPS + "\" tests be run before. An error occurred when attempting to obtain the results of those prerequisites.", otherSubTests, e);
            }
            _Details.BrowseAllResults = BROWSE_RESULTS;
            _Details.SortCapsResults  = SORTCAPS;

            UPnPTestStates state = this._TestState;

            if (BROWSE_RESULTS.LargestContainer == null)
            {
                throw new TestException(this.PRE_BROWSEALL.Name + " failed to find the container with the most child objects. " + this._Name + " requires this value.", BROWSE_RESULTS);
            }

            MediaContainer MC = BROWSE_RESULTS.LargestContainer as MediaContainer;

            if (MC == null)
            {
                throw new TestException(this.PRE_BROWSEALL.Name + " has the largest container as type \"" + BROWSE_RESULTS.LargestContainer.GetType().ToString() + "\" when \"" + this.Name + "\" requires \"" + typeof(MediaContainer).ToString() + "\".", BROWSE_RESULTS);
            }


            ArrayList sortFields = new ArrayList();

            if (SORTCAPS.SortCapabilities == "")
            {
                //arg.TestGroup.AddEvent(LogImportance.Remark, this.Name, "\""+this.Name+"\" has no sorting capabilities.");
            }
            else if (SORTCAPS.SortCapabilities == "*")
            {
                sortFields = (ArrayList)BROWSE_RESULTS.PropertyNames.Clone();
            }
            else
            {
                sortFields.AddRange(GetSortFields(SORTCAPS.SortCapabilities));
            }

            _Details.ExpectedTotalBrowseRequests = 0;
            _Details.SortFields = sortFields;
            int   fieldCount = sortFields.Count;
            IList childList  = BROWSE_RESULTS.LargestContainer.CompleteList;

            _Details.ExpectedTotalBrowseRequests = 0;            //fieldCount * fieldCount * fieldCount;
            uint inc      = (uint)(childList.Count / 3);
            int  firstInc = (fieldCount / 3);

            if (firstInc == 0)
            {
                firstInc = 1;
            }
            for (int numFields = 0; numFields < fieldCount; numFields++)
            {
                for (int first = 0; first < fieldCount; first += firstInc)
                {
                    //for (uint i=0; i < childList.Count; i+=inc)
                    {
                        _Details.ExpectedTotalBrowseRequests++;
                    }
                }
            }
            // add 1 for an unsorted browse
            _Details.ExpectedTotalBrowseRequests++;
            //multiply by 2 because we have 2 rounds to check for consistency in ordered results
            _Details.ExpectedTotalBrowseRequests *= 2;

            //calculate time
            this._ExpectedTestingTime = _Details.ExpectedTotalBrowseRequests * 900;
            arg.ActiveTests.UpdateTimeAndProgress(0);

            if (state <= UPnPTestStates.Running)
            {
                state = UPnPTestStates.Pass;
                try
                {
                    ArrayList round2 = new ArrayList();

                    //perform the standard unsorted browse
                    BrowseInput input = new BrowseInput();
                    input.BrowseFlag     = CpContentDirectory.Enum_A_ARG_TYPE_BrowseFlag.BROWSEDIRECTCHILDREN;
                    input.StartingIndex  = 0;
                    input.ObjectID       = MC.ID;
                    input.RequestedCount = 0;
                    input.Filter         = "*";
                    input.SortCriteria   = "";

                    CdsBrowseSearchResults br = Browse(input, this, arg, CDS, _Details);
                    Round2 r2 = new Round2();
                    r2.Input          = (BrowseInput)input.Clone();
                    r2.PreviousResult = br;
                    round2.Add(r2);

                    for (int numFields = 0; numFields < fieldCount; numFields++)
                    {
                        for (int first = 0; first < fieldCount; first += firstInc)
                        {
                            ArrayList sortSettings = GetSortSettings(sortFields, first, first);
                            input.SortCriteria = GetSortCriteriaString(sortSettings, numFields + first);
                            arg.ActiveTests.UpdateTimeAndProgress(_Details.TotalBrowseRequests * 900);

                            uint ignored;

                            //use this sorter for to determine the expected order of the media objects
                            IMediaSorter sorter         = new MediaSorter(true, input.SortCriteria);
                            IList        expectedSorted = MC.BrowseSorted(0, 0, sorter, out ignored);

                            br = Browse(input, this, arg, CDS, _Details);
                            arg.ActiveTests.UpdateTimeAndProgress(_Details.TotalBrowseRequests * 900);

                            this.CompareResultsAgainstExpected(br, expectedSorted, ref state, arg, input, false);

                            r2                = new Round2();
                            r2.Input          = (BrowseInput)input.Clone();
                            r2.PreviousResult = br;
                            round2.Add(r2);
                        }
                    }

                    //do round2 - check for consistency in results
                    foreach (Round2 r in round2)
                    {
                        br = Browse(r.Input, this, arg, CDS, _Details);
                        arg.ActiveTests.UpdateTimeAndProgress(_Details.TotalBrowseRequests * 900);
                        this.CompareResultsAgainstExpected(br, r.PreviousResult.MediaObjects, ref state, arg, r.Input, true);
                    }
                }
                catch (TerminateEarly te)
                {
                    string reason = "\"" + this.Name + "\" terminating early. Reason => " + te.Message;
                    arg._TestGroup.AddEvent(LogImportance.Critical, this.Name, reason);

                    state = UPnPTestStates.Failed;
                }
            }


            // finish up logging
            this._TestState = state;

            StringBuilder sb = new StringBuilder();

            sb.AppendFormat("\"{0}\" completed", this.Name);

            if (this._TestState <= UPnPTestStates.Running)
            {
                throw new TestException("\"" + this.Name + "\" must have a pass/warn/fail result.", this._TestState);
            }

            switch (this._TestState)
            {
            case UPnPTestStates.Pass:
                sb.Append(" successfully.");
                break;

            case UPnPTestStates.Warn:
                sb.Append(" with warnings.");
                break;

            case UPnPTestStates.Failed:
                sb.Append(" with a failed result.");
                break;
            }

            arg._TestGroup.AddResult(sb.ToString());

            if (this._TestState <= UPnPTestStates.Warn)
            {
                if (_Details.TotalBrowseRequests != _Details.ExpectedTotalBrowseRequests)
                {
                    throw new TestException("TotalBrowseRequests=" + _Details.TotalBrowseRequests.ToString() + " ExpectedTotal=" + _Details.ExpectedTotalBrowseRequests.ToString(), _Details);
                }
            }

            arg._TestGroup.AddEvent(LogImportance.Remark, this.Name, sb.ToString());

            return(this._TestState);
        }