A provider providing parameters by checking the declared Kooboo.Commerce.Rules.ParamAttribute in the class properties.
Inheritance: IRuleParameterProvider
            public void can_discover_nullable_enum()
            {
                var provider = new DefaultRuleParameterProvider();
                var parameters = provider.GetParameters(typeof(ContextModel)).ToList();

                var param = parameters.Find(p => p.Name == "NullableEnumValue");
                Assert.NotNull(param);
                Assert.NotNull(param.ValueSource);

                var values = param.ValueSource.GetValues(param);
                Assert.Equal(3, values.Count());
                Assert.Equal("Value1", values["Value1"]);
                Assert.Equal("Value2", values["Value2"]);
                Assert.Equal("Value3", values["Value3"]);
            }
            public void can_resolve_enum_value()
            {
                var provider = new DefaultRuleParameterProvider();
                var param = provider.GetParameters(typeof(ContextModel))
                                    .FirstOrDefault(p => p.Name == "EnumValue");

                Assert.Equal(MyEnum.Value2, param.ResolveValue(new ContextModel
                {
                    EnumValue = MyEnum.Value2
                }));

                Assert.Equal(MyEnum.Value3, param.ResolveValue(new ContextModel
                {
                    EnumValue = MyEnum.Value3
                }));
            }
            public void can_resolve_nested_object_param_values()
            {
                var provider = new DefaultRuleParameterProvider();
                var parameters = provider.GetParameters(typeof(ContextObject));

                var prop1 = parameters.FirstOrDefault(p => p.Name == "Nested.Prop1");
                var prop2 = parameters.FirstOrDefault(p => p.Name == "Nested.Prop2");

                var context = new ContextObject
                {
                    Nested = new NestedContextObject
                    {
                        Prop1 = 10,
                        Prop2 = "Hello World"
                    }
                };

                var prop1Value = prop1.ValueResolver.ResolveValue(prop1, context);
                Assert.NotNull(prop1Value);
                Assert.Equal(typeof(Int32), prop1Value.GetType());
                Assert.Equal(10, prop1Value);

                var prop2Value = prop2.ValueResolver.ResolveValue(prop2, context);
                Assert.NotNull(prop2Value);
                Assert.Equal(typeof(String), prop2Value.GetType());
                Assert.Equal("Hello World", prop2Value);
            }
            public void can_handle_null_nested_object()
            {
                var provider = new DefaultRuleParameterProvider();
                var parameters = provider.GetParameters(typeof(ContextObject));

                var prop1 = parameters.FirstOrDefault(p => p.Name == "Nested.Prop1");
                var prop2 = parameters.FirstOrDefault(p => p.Name == "Nested.Prop2");

                var context = new ContextObject
                {
                    Nested = null
                };

                object prop1Value = null;

                Assert.DoesNotThrow(() =>
                {
                    prop1Value = prop1.ValueResolver.ResolveValue(prop1, context);
                });
                Assert.Null(prop1Value);

                object prop2Value = null;

                Assert.DoesNotThrow(() =>
                {
                    prop2Value = prop2.ValueResolver.ResolveValue(prop2, context);
                });
                Assert.Null(prop2Value);
            }
            public void should_return_null_for_invalid_reference_key()
            {
                var provider = new DefaultRuleParameterProvider();
                var parameters = provider.GetParameters(typeof(ContextObject));
                var idParam = parameters.FirstOrDefault(p => p.Name == "RequiredProduct.Id");
                var nameParam = parameters.FirstOrDefault(p => p.Name == "RequiredProduct.Name");

                Assert.NotNull(idParam);
                Assert.NotNull(nameParam);

                var context = new ContextObject
                {
                    RequiredProductId = 5
                };

                var id = nameParam.ValueResolver.ResolveValue(idParam, context);
                var name = nameParam.ValueResolver.ResolveValue(nameParam, context);

                Assert.Null(id);
                Assert.Null(name);
            }
            public void can_handle_nullable_reference_key()
            {
                var provider = new DefaultRuleParameterProvider();
                var parameters = provider.GetParameters(typeof(ContextObject));

                var productNameParam = parameters.FirstOrDefault(p => p.Name == "Product.Name");

                // has value
                var context = new ContextObject
                {
                    ProductId = 2
                };

                var productName = productNameParam.ValueResolver.ResolveValue(productNameParam, context);
                Assert.Equal("Product 2", productName);

                // no value
                context = new ContextObject
                {
                    ProductId = null
                };

                productName = productNameParam.ValueResolver.ResolveValue(productNameParam, context);
                Assert.Null(productName);
            }
            public void can_handle_non_nullable_primitive_reference_key()
            {
                var provider = new DefaultRuleParameterProvider();
                var parameters = provider.GetParameters(typeof(ContextObject));

                var productNameParam = parameters.FirstOrDefault(p => p.Name == "RequiredProduct.Name");

                var context = new ContextObject
                {
                    RequiredProductId = 3
                };

                var productName = productNameParam.ValueResolver.ResolveValue(productNameParam, context);
                Assert.Equal("Product 3", productName);
            }