public void CorpusTest(
            [Values(false, true)] bool useLocalSchema,
            [Values(false, true)] bool async)
        {
            RequireServer.Check().Supports(Feature.ClientSideEncryption);

            var corpusSchema = JsonFileReader.Instance.Documents["corpus.corpus-schema.json"];
            var schemaMap    = useLocalSchema ? new BsonDocument("db.coll", corpusSchema) : null;

            using (var client = ConfigureClient())
                using (var clientEncrypted = ConfigureClientEncrypted(schemaMap))
                    using (var clientEncryption = ConfigureClientEncryption(clientEncrypted.Wrapped as MongoClient))
                    {
                        CreateCollection(client, __collCollectionNamespace, new BsonDocument("$jsonSchema", corpusSchema));

                        var corpusKeyLocal     = JsonFileReader.Instance.Documents["corpus.corpus-key-local.json"];
                        var corpusKeyAws       = JsonFileReader.Instance.Documents["corpus.corpus-key-aws.json"];
                        var keyVaultCollection = GetCollection(client, __keyVaultCollectionNamespace);
                        Insert(keyVaultCollection, async, corpusKeyLocal, corpusKeyAws);

                        var corpus       = JsonFileReader.Instance.Documents["corpus.corpus.json"];
                        var corpusCopied = new BsonDocument
                        {
                            corpus.GetElement("_id"),
                            corpus.GetElement("altname_aws"),
                            corpus.GetElement("altname_local")
                        };

                        foreach (var corpusElement in corpus.Elements.Where(c => c.Value.IsBsonDocument))
                        {
                            var corpusValue = corpusElement.Value.DeepClone();
                            var kms         = corpusValue["kms"].AsString;
                            var abbreviatedAlgorithmName = corpusValue["algo"].AsString;
                            var identifier = corpusValue["identifier"].AsString;
                            var allowed    = corpusValue["allowed"].ToBoolean();
                            var value      = corpusValue["value"];
                            var method     = corpusValue["method"].AsString;
                            switch (method)
                            {
                            case "auto":
                                corpusCopied.Add(corpusElement);
                                continue;

                            case "explicit":
                            {
                                var            encryptionOptions = CreateEncryptOptions(abbreviatedAlgorithmName, identifier, kms);
                                BsonBinaryData encrypted         = null;
                                var            exception         = Record.Exception(() =>
                                    {
                                        encrypted = ExplicitEncrypt(
                                            clientEncryption,
                                            encryptionOptions,
                                            value,
                                            async);
                                    });
                                if (allowed)
                                {
                                    exception.Should().BeNull();
                                    encrypted.Should().NotBeNull();
                                    corpusValue["value"] = encrypted;
                                }
                                else
                                {
                                    exception.Should().NotBeNull();
                                }
                                corpusCopied.Add(new BsonElement(corpusElement.Name, corpusValue));
                            }
                            break;

                            default:
                                throw new ArgumentException($"Unsupported method name {method}.", nameof(method));
                            }
                        }

                        var coll = GetCollection(clientEncrypted, __collCollectionNamespace);
                        Insert(coll, async, corpusCopied);

                        var corpusDecrypted = Find(coll, new BsonDocument(), async).Single();
                        corpusDecrypted.Should().Be(corpus);

                        var corpusEncryptedExpected = JsonFileReader.Instance.Documents["corpus.corpus-encrypted.json"];
                        coll = GetCollection(client, __collCollectionNamespace);
                        var corpusEncryptedActual = Find(coll, new BsonDocument(), async).Single();
                        foreach (var expectedElement in corpusEncryptedExpected.Elements.Where(c => c.Value.IsBsonDocument))
                        {
                            var expectedElementValue = expectedElement.Value;
                            var expectedAlgorithm    = ParseAlgorithm(expectedElementValue["algo"].AsString);
                            var expectedAllowed      = expectedElementValue["allowed"].ToBoolean();
                            var expectedValue        = expectedElementValue["value"];
                            var actualValue          = corpusEncryptedActual.GetValue(expectedElement.Name)["value"];

                            switch (expectedAlgorithm)
                            {
                            case EncryptionAlgorithm.AEAD_AES_256_CBC_HMAC_SHA_512_Deterministic:
                                actualValue.Should().Be(expectedValue);
                                break;

                            case EncryptionAlgorithm.AEAD_AES_256_CBC_HMAC_SHA_512_Random:
                                if (expectedAllowed)
                                {
                                    actualValue.Should().NotBe(expectedValue);
                                }
                                break;

                            default:
                                throw new ArgumentException($"Unsupported expected algorithm {expectedAllowed}.", nameof(expectedAlgorithm));
                            }

                            if (expectedAllowed)
                            {
                                var actualDecryptedValue   = ExplicitDecrypt(clientEncryption, actualValue.AsBsonBinaryData, async);
                                var expectedDecryptedValue = ExplicitDecrypt(clientEncryption, expectedValue.AsBsonBinaryData, async);
                                actualDecryptedValue.Should().Be(expectedDecryptedValue);
                            }
                            else
                            {
                                actualValue.Should().Be(expectedValue);
                            }
                        }
                    }

            EncryptOptions CreateEncryptOptions(string algorithm, string identifier, string kms)
            {
                Guid?  keyId         = null;
                string alternateName = null;

                if (identifier == "id")
                {
                    switch (kms)
                    {
                    case "local":
                        keyId = GuidConverter.FromBytes(Convert.FromBase64String("LOCALAAAAAAAAAAAAAAAAA=="), GuidRepresentation.Standard);
                        break;

                    case "aws":
                        keyId = GuidConverter.FromBytes(Convert.FromBase64String("AWSAAAAAAAAAAAAAAAAAAA=="), GuidRepresentation.Standard);
                        break;

                    default:
                        throw new ArgumentException($"Unsupported kms type {kms}.");
                    }
                }
                else if (identifier == "altname")
                {
                    alternateName = kms;
                }
                else
                {
                    throw new ArgumentException($"Unsupported identifier {identifier}.", nameof(identifier));
                }

                return(new EncryptOptions(ParseAlgorithm(algorithm).ToString(), alternateName, keyId));
            }

            EncryptionAlgorithm ParseAlgorithm(string algorithm)
            {
                switch (algorithm)
                {
                case "rand":
                    return(EncryptionAlgorithm.AEAD_AES_256_CBC_HMAC_SHA_512_Random);

                case "det":
                    return(EncryptionAlgorithm.AEAD_AES_256_CBC_HMAC_SHA_512_Deterministic);

                default:
                    throw new ArgumentException($"Unsupported algorithm {algorithm}.");
                }
            }
        }