private static bool AssertionForBool(AssertInstanceReference instance, out InvocationExpressionSyntax expression)
        {
            expression = null;
            if (instance.ActualType == typeof(bool))
            {
                var tValue = (bool)instance.Value;
                if (tValue)
                {
                    expression = AssertionTrue(instance.AssertionName, instance.Expression, $"{instance.Path} must be true");
                }
                else
                {
                    expression = AssertionFalse(instance.AssertionName, instance.Expression, $"{instance.Path} must be false");
                }
            }
            if (instance.ActualType == typeof(bool?))
            {
                var tValue = (bool?)instance.Value;
                if (tValue.Value)
                {
                    expression = AssertionTrue(instance.AssertionName, instance.Expression, $"{instance.Path} must be true");
                }
                else
                {
                    expression = AssertionFalse(instance.AssertionName, instance.Expression, $"{instance.Path} must be false");
                }
            }

            return(expression != null);
        }
        public IEnumerable <(string, AssertInstanceReference)> Items()
        {
            var enumer   = Value as System.Collections.IEnumerable;
            var declared = ActualType.GetCollectionElementType();
            int idx      = 0;

            foreach (var enumeration in enumer)
            {
                var instance = new AssertInstanceReference(
                    enumeration,
                    declared,
                    IdentifierName($"r{IterationDepth}_{idx}"),
                    $"item #{idx} of {Path}",
                    Usings)

                {
                    AssertionName  = AssertionName,
                    IterationDepth = this.IterationDepth + 1
                };

                yield return($"r{IterationDepth}_{idx}", instance);

                idx++;
            }
        }
        private void Visit(CommandBase command)
        {
            if (command is End)
            {
                TheEnd();
            }
            else
            {
                var validatedProperties = GetValidatedProperties(command);
                if (validatedProperties.Length == 0)
                {
                    Then(command); //needed to do not overwhelm braces
                }
                else
                {
                    var invokations = new List <InvocationExpressionSyntax>();
                    foreach (var validatedProperty in validatedProperties)
                    {
                        if (_optOuts.Contains(validatedProperty.Item1.OptOutFlag))
                        {
                            continue;
                        }

                        var commandDescription = string.IsNullOrEmpty(command.Annotation)? command.GetType().Name:$"'{command.Annotation}'";

                        var meaning = validatedProperty.Item1.Meaning ?? $"property {validatedProperty.Item2.Name}";

                        var propMeaning =
                            validatedProperty.Item1.Meaning ??
                            $"{meaning} of command {commandDescription}";

                        var instance = new AssertInstanceReference
                                       (
                            validatedProperty.Item2.GetValue(command),
                            validatedProperty.Item2.PropertyType,
                            MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
                                                   IdentifierName("c"),
                                                   IdentifierName(validatedProperty.Item2.Name)),
                            propMeaning,
                            _usings
                                       );
                        var assertions = TypeAssertionGenerator.AssertionFor(instance)
                                         .ToArray();
                        invokations.AddRange(assertions);
                        invokations.Add(null);
                    }
                    Then(command, invokations);
                }
            }
        }
        internal static IEnumerable <InvocationExpressionSyntax> AssertionFor(AssertInstanceReference instance)
        {
            if (instance.Value == null)
            {
                yield return(AssertionNull(instance.AssertionName, instance.Expression, $"{instance.Path} must be null"));
            }
            else
            {
                if (!instance.ActualType.IsValueType)
                {
                    yield return(AssertionNotNull(instance.AssertionName, instance.Expression, $"{instance.Path} must not be null"));
                }

                foreach (var expr in AssertionForNotNull(instance))
                {
                    yield return(expr);
                }
            }
        }
        public IEnumerable <AssertInstanceReference> Dictionary()
        {
            var enumer     = Value as System.Collections.IDictionary;
            var declaredKv = ActualType.GetDictionaryParameters();

            foreach (var key in enumer.Keys)
            {
                var value    = enumer[key];
                var instance = new AssertInstanceReference(
                    value,
                    declaredKv.Item1,
                    Bracket(Expression, declaredKv.Item1, key),
                    $"value for {key} in {Path}",
                    Usings)

                {
                    AssertionName  = AssertionName,
                    IterationDepth = this.IterationDepth + 1
                };

                yield return(instance);
            }
        }
        private static IEnumerable <InvocationExpressionSyntax> AssertionForNotNull(AssertInstanceReference instance)
        {
            if (AssertionForBool(instance, out var expr))
            {
                yield return(expr);

                yield break;
            }

            if (instance.ActualType.IsInlineable())
            {
                var inlined = TypeInitConstructor.Construct(instance.ActualType, instance.Value, instance.Usings);
                yield return(AssertionEquals(instance.AssertionName, instance.Expression, inlined, $"{instance.Path} has invalid value"));

                yield break;
            }

            if (instance.ActualType.IsDictionary())
            {
                var dicParams = instance.ActualType.GetDictionaryParameters();
                yield return(AssertionEquals(
                                 instance.AssertionName,
                                 MemberAccessExpression(
                                     SyntaxKind.SimpleMemberAccessExpression,
                                     instance.Expression,
                                     IdentifierName(nameof(IDictionary.Count)))
                                 , LiteralExpression(SyntaxKind.NumericLiteralExpression,
                                                     Literal(instance.KeysCount())),
                                 $"{instance.Path} has invalid size"));

                if (dicParams.Item1.IsInlineable())
                {
                    foreach (var dictionaryItem in instance.Dictionary())
                    {
                        foreach (var check in AssertionFor(dictionaryItem))
                        {
                            yield return(check);
                        }
                    }
                }
                yield break;
            }

            if (instance.ActualType.IsEnumerable())
            {
                var arguments = new List <ExpressionSyntax>();
                arguments.Add((instance.Expression));
                arguments.Add((T($"{instance.Path} must be composed correctly")));

                foreach (var lValueTuple in instance.Items())
                {
                    var setOfChecks = AssertionFor(lValueTuple.Item2).ToArray();
                    arguments.Add((WrapIntoLambda(setOfChecks, lValueTuple.Item1)));
                }

                yield return(AssertForCollection(instance.AssertionName, arguments.ToArray()));

                yield break;
            }

            foreach (var property in instance.Properties())
            {
                foreach (var assrt in AssertionFor(property))
                {
                    yield return(assrt);
                }
            }
        }