public void Parser_Multiples()
        {
            CommandLineParser parser;
            IEnumerable<ArgumentInstance> instances;
            TestLogger logger;

            string[] args = new string[] { "zzzv1", "zzzv2", "zzzv3" };

            // 1. Don't allow multiples
            ArgumentDescriptor d1 = new ArgumentDescriptor("id", new string[] { "zzz" }, true, "desc1", false /* no multiples */);
            parser = new CommandLineParser(new ArgumentDescriptor[] { d1 }, false);

            logger = CheckProcessingFails(parser, args);

            logger.AssertSingleErrorExists("zzzv2", "v1");
            logger.AssertSingleErrorExists("zzzv3", "v1");
            logger.AssertErrorsLogged(2);

            // 2. Allow multiples
            d1 = new ArgumentDescriptor("id", new string[] { "zzz" }, true, "desc1", true /* allow multiple */);
            parser = new CommandLineParser(new ArgumentDescriptor[] { d1 }, true);
            logger = new TestLogger();
            instances = CheckProcessingSucceeds(parser, logger, args);

            AssertExpectedValues("id", instances, "v1", "v2", "v3");
            AssertExpectedInstancesCount(3, instances);
        }
        public void Parser_UnrecognizedArguments()
        {
            CommandLineParser parser;
            IEnumerable<ArgumentInstance> instances;
            TestLogger logger;

            string[] args = new string[] { "/a:XXX", "/unrecognized" };

            ArgumentDescriptor d1 = new ArgumentDescriptor("id1", new string[] { "/a:" }, true, "desc1", false);

            // 1. Don't allow unrecognized
            parser = new CommandLineParser(new ArgumentDescriptor[] { d1 }, false);

            logger = CheckProcessingFails(parser, args);

            logger.AssertSingleErrorExists("/unrecognized");
            logger.AssertErrorsLogged(1);

            // 2. Allow unrecognized
            parser = new CommandLineParser(new ArgumentDescriptor[] { d1 }, true);
            logger = new TestLogger();
            instances = CheckProcessingSucceeds(parser, logger, args);

            AssertExpectedValue("id1", "XXX", instances);
            AssertExpectedInstancesCount(1, instances);
            logger.AssertMessagesLogged(0); // expecting unrecognized arguments to be ignored silently
        }
        public void Parser_DuplicateDescriptorIds()
        {
            ArgumentDescriptor d1 = new ArgumentDescriptor("id1", new string[] { "a" }, true, "desc1", false);
            ArgumentDescriptor d2 = new ArgumentDescriptor("id1", new string[] { "b" }, true, "desc2", false);

            AssertException.Expects<ArgumentException>(() => new CommandLineParser(
                new ArgumentDescriptor[] { d1, d2 }, true));
        }
        public void Parser_CaseSensitivity()
        {
            string[] args = new string[] { "aaa:all lowercase", "AAA:all uppercase", "aAa: mixed case" };

            ArgumentDescriptor d1 = new ArgumentDescriptor("id", new string[] { "AAA:" }, true/* allow multiples */ , "desc1", true /* allow multiple */);
            CommandLineParser parser = new CommandLineParser(new ArgumentDescriptor[] { d1 }, true /* allow unrecognized */);

            // Act
            IEnumerable<ArgumentInstance> instances = CheckProcessingSucceeds(parser, new TestLogger(), args);

            AssertExpectedValue("id", "all uppercase", instances);
            AssertExpectedInstancesCount(1, instances);
        }
Exemple #5
0
        public void Parser_Verbs_Required()
        {
            CommandLineParser parser;
            IEnumerable <ArgumentInstance> instances;
            TestLogger logger;

            var emptyArgs          = new string[] { };
            var matchingPrefixArgs = new string[] { "AAAa" };

            // 1a. Argument is required but is missing -> error
            var d1 = new ArgumentDescriptor("id", new string[] { "AAA" }, true /* required */, "desc1", false /* no multiples */, true);

            parser = new CommandLineParser(new ArgumentDescriptor[] { d1 }, false);
            logger = CheckProcessingFails(parser, emptyArgs);

            logger.AssertSingleErrorExists("desc1");
            logger.AssertErrorsLogged(1);

            // 1b. Argument is required but is only partial match -> missing -> error2
            logger = CheckProcessingFails(parser, matchingPrefixArgs);

            logger.AssertSingleErrorExists("desc1"); // missing arg
            logger.AssertSingleErrorExists("AAAa");  // unrecognized since not exact match
            logger.AssertErrorsLogged(2);

            // 2a. Argument is not required, missing -> ok
            d1        = new ArgumentDescriptor("id", new string[] { "AAA" }, false /* not required */, "desc1", false /* no multiples */, true);
            parser    = new CommandLineParser(new ArgumentDescriptor[] { d1 }, true);
            logger    = new TestLogger();
            instances = CheckProcessingSucceeds(parser, logger, emptyArgs);

            AssertExpectedInstancesCount(0, instances);

            // 2b. Argument is not required, partial -> missing -> ok
            logger    = new TestLogger();
            instances = CheckProcessingSucceeds(parser, logger, matchingPrefixArgs);

            AssertExpectedInstancesCount(0, instances);
        }
Exemple #6
0
        private static void HandleObjectType(
            ITypeCompletionContext completionContext,
            ObjectTypeDefinition definition,
            ISpatialConvention convention)
        {
            foreach (var field in definition.Fields)
            {
                foreach (var arg in field.Arguments)
                {
                    if (arg.Type is not null &&
                        completionContext.IsNamedType <IGeoJsonInputType>(arg.Type))
                    {
                        arg.Formatters.Add(
                            new GeometryTransformerInputFormatter(
                                convention.TransformerFactory,
                                convention.DefaultSrid));
                    }
                }

                if (field.Type is not null &&
                    completionContext.IsNamedType <IGeoJsonObjectType>(field.Type))
                {
                    var argument =
                        ArgumentDescriptor.New(
                            completionContext.DescriptorContext,
                            CrsFieldName);

                    argument
                    .Type <IntType>()
                    .Description(Transformation_Argument_Crs_Description);

                    field.Arguments.Add(argument.CreateDefinition());
                    field.MiddlewareComponents.Insert(0,
                                                      FieldClassMiddlewareFactory.Create <GeometryTransformationMiddleware>(
                                                          (typeof(IGeometryTransformerFactory), convention.TransformerFactory),
                                                          (typeof(int), convention.DefaultSrid)));
                }
            }
        }
        public void CmdLineArgProperties_DynamicProperties()
        {
            // Arrange
            TestLogger logger = new TestLogger();
            IList<ArgumentInstance> args = new List<ArgumentInstance>();

            ArgumentDescriptor dummyDescriptor = new ArgumentDescriptor("dummy", new string[] { "dummy prefix" }, false, "dummy desc", true);
            ArgumentDescriptor dummyDescriptor2 = new ArgumentDescriptor("dummy2", new string[] { "dummy prefix 2" }, false, "dummy desc 2", true);

            args.Add(new ArgumentInstance(dummyDescriptor, "should be ignored"));
            args.Add(new ArgumentInstance(dummyDescriptor2, "should be ignored"));

            AddDynamicArguments(args, "key1=value1", "key2=value two with spaces");

            // Act
            IAnalysisPropertyProvider provider = CheckProcessingSucceeds(args, logger);

            // Assert
            provider.AssertExpectedPropertyValue("key1", "value1");
            provider.AssertExpectedPropertyValue("key2", "value two with spaces");

            provider.AssertExpectedPropertyCount(2);
        }
Exemple #8
0
        public void Parser_Verbs_Multiples()
        {
            CommandLineParser parser;
            IEnumerable <ArgumentInstance> instances;
            TestLogger logger;

            string[] args = new string[] { "verb" };

            ArgumentDescriptor verb1 = new ArgumentDescriptor("v1", new string[] { "noMult" }, false /* required */, "noMult desc", false /* no multiples */, true);
            ArgumentDescriptor verb2 = new ArgumentDescriptor("v2", new string[] { "multOk" }, false /* required */, "multOk desc", true /* allow multiples */, true);

            parser = new CommandLineParser(new ArgumentDescriptor[] { verb1, verb2 }, true /* allow unrecognised */);

            // 1. Allowed multiples
            logger    = new TestLogger();
            instances = CheckProcessingSucceeds(parser, logger, "multOk", "multOk");
            AssertExpectedInstancesCount(2, instances);

            // 2. Disallowed multiples
            logger = CheckProcessingFails(parser, new string[] { "noMult", "noMult" });
            logger.AssertSingleErrorExists("noMult");
            logger.AssertErrorsLogged(1);
        }
        public void CmdLineArgProperties_DynamicProperties()
        {
            // Arrange
            var logger = new TestLogger();
            IList <ArgumentInstance> args = new List <ArgumentInstance>();

            var dummyDescriptor  = new ArgumentDescriptor("dummy", new string[] { "dummy prefix" }, false, "dummy desc", true);
            var dummyDescriptor2 = new ArgumentDescriptor("dummy2", new string[] { "dummy prefix 2" }, false, "dummy desc 2", true);

            args.Add(new ArgumentInstance(dummyDescriptor, "should be ignored"));
            args.Add(new ArgumentInstance(dummyDescriptor2, "should be ignored"));

            AddDynamicArguments(args, "key1=value1", "key2=value two with spaces");

            // Act
            var provider = CheckProcessingSucceeds(args, logger);

            // Assert
            provider.AssertExpectedPropertyValue("key1", "value1");
            provider.AssertExpectedPropertyValue("key2", "value two with spaces");

            provider.AssertExpectedPropertyCount(2);
        }
        public void Parser_Verbs_ExactMatchesOnly()
        {
            CommandLineParser parser;
            IEnumerable<ArgumentInstance> instances;
            TestLogger logger;

            ArgumentDescriptor verb1 = new ArgumentDescriptor("v1", new string[] { "begin" }, false /* not required */, "desc1", false /* no multiples */, true);
            parser = new CommandLineParser(new ArgumentDescriptor[] { verb1 }, true /* allow unrecognised */);

            // 1. Exact match -> matched
            logger = new TestLogger();
            instances = CheckProcessingSucceeds(parser, logger, "begin");
            AssertExpectedValue("v1", "", instances);
            AssertExpectedInstancesCount(1, instances);

            // 2. Partial match -> not matched
            logger = new TestLogger();
            instances = CheckProcessingSucceeds(parser, logger, "beginX");
            AssertExpectedInstancesCount(0, instances);

            // 3. Combination -> only exact matches matched
            logger = new TestLogger();
            instances = CheckProcessingSucceeds(parser, logger, "beginX", "begin", "beginY");
            Assert.AreEqual(string.Empty, instances.First().Value, "Value for verb should be empty");
            AssertExpectedInstancesCount(1, instances);
            AssertExpectedValue("v1", "", instances);
        }
 public static ArgumentDescriptor ToDescriptor(
     this ArgumentDefinition definition,
     IDescriptorContext context)
 => ArgumentDescriptor.From(context, definition);
Exemple #12
0
        private bool TryParseArguments(ParameterInfo[] parameters, string[] arguments, out object[] parsedArguments)
        {
            parsedArguments = null;
            if (arguments.Length > parameters.Length)
            {
                return(false);
            }

            var args = new ArgumentDescriptor[parameters.Length];

            var positionalArgumentIndex = 0;
            var namedArgumentDetected   = false;
            var pattern = new Regex(@"^([a-zA-Z0-9_]+)=(.+)");

            foreach (var argument in arguments)
            {
                object result;
                int    position;
                string valueToParse;
                // check if it's a named argument
                var m = pattern.Match(argument);
                if (m.Success)
                {
                    namedArgumentDetected = true;
                    var name  = m.Groups[1].Value;
                    var param = parameters.SingleOrDefault(x => x.Name == name);

                    if (param == null)
                    {
                        return(false);
                    }

                    if (args[param.Position].IsParsed)
                    {
                        throw new ArgumentException("Named argument `{0}' specified multiple times", name);
                    }

                    position     = param.Position;
                    valueToParse = m.Groups[2].Value;
                }
                else
                {
                    if (namedArgumentDetected)
                    {
                        // this is a serious error
                        throw new ArgumentException("Named arguments must appear after the positional arguments");
                    }

                    position     = positionalArgumentIndex++;
                    valueToParse = argument;
                }

                if (!SmartParser.Instance.TryParse(valueToParse, parameters[position].ParameterType, out result))
                {
                    return(false);
                }

                args[position].IsParsed = true;
                args[position].Value    = result;
            }

            for (var i = 0; i < args.Length; i++)
            {
                if (args[i].IsParsed)
                {
                    continue;
                }

                if (!parameters[i].HasDefaultValue)
                {
                    return(false);
                }

                args[i].IsParsed = true;
                args[i].Value    = parameters[i].DefaultValue;
            }

            parsedArguments = args.Select(x => x.Value).ToArray();
            return(true);
        }
        private IEnumerable<ArgumentDescriptor> RetrieveCommandArguments(Type runnableType)
        {
            var runnableProperties = runnableType.GetProperties();
            var runnablePropertiesWithAttribute = runnableProperties.Select(property => new
            {
                PropertyInformation = property,
                Attribute = property.GetCustomAttributes(typeof (ParameterAttribute), true)
                                    .OfType<ParameterAttribute>()
                                    .SingleOrDefault()
            });
            var properties = runnablePropertiesWithAttribute.Where(property => property.Attribute != null);

            var position = 0;
            foreach (var property in properties)
            {
                var descriptor = new ArgumentDescriptor
                {
                    ArgumentName = property.Attribute.PropertyName,
                    ArgumentType = property.PropertyInformation.PropertyType,
                    DefaultValue = null,
                    IsOptional = true,
                    Position = position
                };

                yield return descriptor;

                position++;
            }
        }
Exemple #14
0
 private static string DirectionToString(ArgumentDescriptor.EArgDirection dir)
 {
     switch (dir)
     {
         case ArgumentDescriptor.EArgDirection.In: 
             return "in";
         case ArgumentDescriptor.EArgDirection.InOut:
             return "inout";
         case ArgumentDescriptor.EArgDirection.Out:
             return "out";
         default:
             throw new NotImplementedException();
     }
 }
Exemple #15
0
 protected override string Generate(ArgumentDescriptor descriptor)
 {
     return($"ctx.{nameof(IResolverContext.FieldSelection)}");
 }
Exemple #16
0
        private Task PublishAsync(IEnumerable <HandlerDescriptor> handlers, ArgumentDescriptor argument, object eventPayload, bool isEnvelopeDelayUsed)
        {
            try
            {
                bool hasContextHandler  = handlers.Any(d => d.IsContext);
                bool hasEnvelopeHandler = hasContextHandler || handlers.Any(d => d.IsEnvelope);

                object   payload  = eventPayload;
                object   context  = null;
                Envelope envelope = null;

                IEvent eventWithKey = null;
                if (argument.IsContext)
                {
                    // If passed argument is context, throw.
                    throw Ensure.Exception.NotSupported("PersistentEventDispatcher doesn't support passing in event handler context.");
                }
                else
                {
                    // If passed argument is not context, try to create it if needed.
                    if (argument.IsEnvelope)
                    {
                        // If passed argument is envelope, extract payload.
                        envelope = (Envelope)payload;
                        payload  = envelope.Body;
                    }
                    else
                    {
                        eventWithKey       = payload as IEvent;
                        hasEnvelopeHandler = hasEnvelopeHandler || eventWithKey != null;

                        // If passed argument is not envelope, try to create it if needed.
                        if (hasEnvelopeHandler)
                        {
                            envelope = EnvelopeFactory.Create(payload, argument.ArgumentType);
                        }
                    }

                    if (hasContextHandler)
                    {
                        Type contextType = typeof(DefaultEventHandlerContext <>).MakeGenericType(argument.ArgumentType);
                        context = Activator.CreateInstance(contextType, envelope, this, this);
                    }
                }

                if (eventWithKey == null)
                {
                    eventWithKey = payload as IEvent;
                }

                log.Info(eventWithKey, "Got an event.");

                // If isEnvelopeDelayUsed, try to schedule the execution.
                // If succeeded, return.
                if (isEnvelopeDelayUsed && TrySchedule(envelope, context, handlers, argument))
                {
                    return(Async.CompletedTask);
                }

                // Distribute the execution.
                return(DistributeExecution(payload, context, envelope, eventWithKey, handlers));
            }
            catch (Exception e)
            {
                DispatcherExceptionHandlers.Handle(e);
                return(Async.CompletedTask);
            }
        }
 public static ArgumentDescriptorAssertions Should(this ArgumentDescriptor instance)
 => new ArgumentDescriptorAssertions(instance);
 protected override string Generate(
     ArgumentDescriptor descriptor)
 {
     return("ct");
 }
        public void Parser_Required()
        {
            CommandLineParser parser;
            IEnumerable<ArgumentInstance> instances;
            TestLogger logger;

            string[] args = new string[] {  };

            // 1. Argument is required
            ArgumentDescriptor d1 = new ArgumentDescriptor("id", new string[] { "AAA" }, true /* required */, "desc1", false /* no multiples */);
            parser = new CommandLineParser(new ArgumentDescriptor[] { d1 }, false);

            logger = CheckProcessingFails(parser, args);

            logger.AssertSingleErrorExists("desc1");
            logger.AssertErrorsLogged(1);

            // 2. Argument is not required
            d1 = new ArgumentDescriptor("id", new string[] { "AAA" }, false /* not required */, "desc1", false /* no multiples */);
            parser = new CommandLineParser(new ArgumentDescriptor[] { d1 }, true);
            logger = new TestLogger();
            instances = CheckProcessingSucceeds(parser, logger, args);

            AssertExpectedInstancesCount(0, instances);
        }
Exemple #20
0
        private bool TrySchedule(Envelope envelope, object handlerContext, IEnumerable <HandlerDescriptor> handlers, ArgumentDescriptor argument)
        {
            if (schedulingProvider.IsLaterExecutionRequired(envelope))
            {
                log.Info(envelope, "Scheduling for later execution.");

                ScheduleEventContext context = new ScheduleEventContext(handlers, argument, envelope, handlerContext, OnScheduledEvent);
                schedulingProvider.Schedule(context);
                return(true);
            }

            return(false);
        }
            public void ShouldReturnSpecifiedArgumentsInRunnableDescriptorAttribute_WhenOneRunnableIsPassed()
            {
                // Act + Arrange
                var result = underTest.GetCommandDescriptors().SingleOrDefault();

                // Assert
                Assert.That(result, Is.Not.Null);

                var myParameterDescriptor = new ArgumentDescriptor()
                {
                    ArgumentName = "my-parameter",
                    ArgumentType = typeof (String),
                    DefaultValue = null,
                    IsOptional = true,
                    Position = 0
                };

                var anotherParameterDescriptor = new ArgumentDescriptor
                {
                    ArgumentName = "another-parameter",
                    ArgumentType = typeof (Int32),
                    DefaultValue = null,
                    IsOptional = true,
                    Position = 1
                };

                var parameters = Array(myParameterDescriptor, anotherParameterDescriptor);

                Assert.That(result.Arguments, Is.EquivalentTo(parameters));
            }
        public void Parser_Verbs_Multiples()
        {
            CommandLineParser parser;
            IEnumerable<ArgumentInstance> instances;
            TestLogger logger;

            ArgumentDescriptor verb1 = new ArgumentDescriptor("v1", new string[] { "noMult" }, false /* required */, "noMult desc", false /* no multiples */, true);
            ArgumentDescriptor verb2 = new ArgumentDescriptor("v2", new string[] { "multOk" }, false /* required */, "multOk desc", true /* allow multiples */, true);

            parser = new CommandLineParser(new ArgumentDescriptor[] { verb1, verb2 }, true /* allow unrecognised */ );

            // 1. Allowed multiples
            logger = new TestLogger();
            instances = CheckProcessingSucceeds(parser, logger, "multOk", "multOk");
            AssertExpectedInstancesCount(2, instances);

            // 2. Disallowed multiples
            logger = CheckProcessingFails(parser, new string[] { "noMult", "noMult" });
            logger.AssertSingleErrorExists("noMult");
            logger.AssertErrorsLogged(1);
        }
Exemple #23
0
        private async Task HandleInternalAsync(HandlerDescriptor handler, ArgumentDescriptor argument, object commandPayload, bool isPersistenceUsed, bool isEnvelopeDelayUsed)
        {
            try
            {
                bool hasContextHandler  = handler.IsContext;
                bool hasEnvelopeHandler = hasContextHandler || handler.IsEnvelope;

                object   payload  = commandPayload;
                object   context  = null;
                Envelope envelope = null;

                ICommand commandWithKey = null;
                if (argument.IsContext)
                {
                    // If passed argument is context, throw.
                    log.Fatal("Passed in a context object.");
                    throw Ensure.Exception.NotSupported("PersistentCommandDispatcher doesn't support passing in a command handler context.");
                }
                else
                {
                    // If passed argument is not context, try to create it if needed.
                    if (argument.IsEnvelope)
                    {
                        // If passed argument is envelope, extract payload.
                        envelope = (Envelope)payload;
                        payload  = envelope.Body;
                    }
                    else
                    {
                        commandWithKey     = payload as ICommand;
                        hasEnvelopeHandler = hasEnvelopeHandler || commandWithKey != null;

                        // If passed argument is not envelope, try to create it if needed.
                        if (hasEnvelopeHandler)
                        {
                            envelope = EnvelopeFactory.Create(payload, argument.ArgumentType);
                        }
                    }

                    if (hasContextHandler)
                    {
                        log.Fatal("Context handler not supported.");
                        throw Ensure.Exception.NotSupported("PersistentCommandDispatcher doesn't support command handler context.");
                    }
                }

                if (commandWithKey == null)
                {
                    commandWithKey = payload as ICommand;
                }

                log.Info(commandWithKey, "Got a command.");
                log.Info(commandWithKey, "Execution on the handler '{0}'.", handler);

                // If we have command with the key, serialize it for persisten delivery.
                if (store != null && isPersistenceUsed && commandWithKey != null)
                {
                    string serializedEnvelope = await formatter.SerializeAsync(envelope);

                    store.Save(new CommandModel(commandWithKey.Key, serializedEnvelope));

                    log.Debug(commandWithKey, "Saved to the store.");
                }

                // If isEnvelopeDelayUsed, try to schedule the execution.
                // If succeeded, return.
                if (isEnvelopeDelayUsed && TrySchedule(envelope, handler, argument))
                {
                    return;
                }

                // Distribute the execution.
                DistributeExecution(payload, context, envelope, commandWithKey, handler);
            }
            catch (Exception e)
            {
                DispatcherExceptionHandlers.Handle(e);
            }
        }
        public void Parser_Verbs_Required()
        {
            CommandLineParser parser;
            IEnumerable<ArgumentInstance> instances;
            TestLogger logger;

            string[] emptyArgs = new string[] { };
            string[] matchingPrefixArgs = new string[] { "AAAa" };

            // 1a. Argument is required but is missing -> error
            ArgumentDescriptor d1 = new ArgumentDescriptor("id", new string[] { "AAA" }, true /* required */, "desc1", false /* no multiples */, true);
            parser = new CommandLineParser(new ArgumentDescriptor[] { d1 }, false);
            logger = CheckProcessingFails(parser, emptyArgs);

            logger.AssertSingleErrorExists("desc1");
            logger.AssertErrorsLogged(1);

            // 1b. Argument is required but is only partial match -> missing -> error2
            logger = CheckProcessingFails(parser, matchingPrefixArgs);

            logger.AssertSingleErrorExists("desc1"); // missing arg
            logger.AssertSingleErrorExists("AAAa"); // unrecognized since not exact match
            logger.AssertErrorsLogged(2);


            // 2a. Argument is not required, missing -> ok
            d1 = new ArgumentDescriptor("id", new string[] { "AAA" }, false /* not required */, "desc1", false /* no multiples */, true);
            parser = new CommandLineParser(new ArgumentDescriptor[] { d1 }, true);
            logger = new TestLogger();
            instances = CheckProcessingSucceeds(parser, logger, emptyArgs);

            AssertExpectedInstancesCount(0, instances);

            // 2b. Argument is not required, partial -> missing -> ok
            logger = new TestLogger();
            instances = CheckProcessingSucceeds(parser, logger, matchingPrefixArgs);

            AssertExpectedInstancesCount(0, instances);
        }
Exemple #25
0
 protected override string Generate(ArgumentDescriptor descriptor)
 {
     return($"ctx.{nameof(IResolverContext.ObjectType)}");
 }
        public void Parser_OverlappingVerbsAndPrefixes()
        {
            // Tests handling of verbs and non-verbs that start with the same values
            CommandLineParser parser;
            IEnumerable<ArgumentInstance> instances;
            TestLogger logger;

            ArgumentDescriptor verb1 = new ArgumentDescriptor("v1", new string[] { "X" }, false /* not required */, "verb1 desc", false /* no multiples */, true);
            ArgumentDescriptor prefix1 = new ArgumentDescriptor("p1", new string[] { "XX" }, false /* not required */, "prefix1 desc", false /* no multiples */, false);
            ArgumentDescriptor verb2 = new ArgumentDescriptor("v2", new string[] { "XXX" }, false /* not required */, "verb2 desc", false /* no multiples */, true);
            ArgumentDescriptor prefix2 = new ArgumentDescriptor("p2", new string[] { "XXXX" }, false /* not required */, "prefix2 desc", false /* no multiples */, false);
            
            // NOTE: this test only works because the descriptors are supplied to parser ordered
            // by decreasing prefix length
            parser = new CommandLineParser(new ArgumentDescriptor[] { prefix2, verb2, prefix1, verb1 }, true /* allow unrecognised */);

            // 1. Exact match -> matched
            logger = new TestLogger();
            instances = CheckProcessingSucceeds(parser, logger,
                "X", // verb 1 - exact match
                "XXAAA", // prefix 1 - has value A,
                "XXX", // verb 2 - exact match,
                "XXXXB" // prefix 2 - has value B,
                );

            AssertExpectedValue("v1", "", instances);
            AssertExpectedValue("p1", "AAA", instances);
            AssertExpectedValue("v2", "", instances);
            AssertExpectedValue("p2", "B", instances);
        }