public void ValidatePregeneratedCouponCodesHasNoErrors(string code)
        {
            var opts = new Options();
            var ccb = new CouponCodeBuilder();
            var output = ccb.Validate(code, opts);

            // check code and validation are the same
            Assert.IsNotNullOrEmpty(output, string.Format("Expected test case {0} to be not null or empty.", code));
            Assert.AreEqual(code, output, string.Format("Expected test case {0} to ensure that the generated code and validated code match.", code));
        }
        public void InvalidCouponCodeReturnEmptyString()
        {
            var opts = new Options();
            var ccb = new CouponCodeBuilder();

            // valid is "9Y46-9M8E-UQB8"
            var output = ccb.Validate("9Y46-9M8E-UQBA", opts);

            // check output is empty
            Assert.IsEmpty(output);
        }
        public void GenerateValidCouponCodesAlsoValidates(int counter)
        {
            var opts = new Options();
            var ccb = new CouponCodeBuilder();
            var badWords = ccb.BadWordsList;

            var code = ccb.Generate(opts);
            var output = ccb.Validate(code, opts);

            Console.WriteLine(code);

            // check code and validation are the same
            Assert.IsNotNullOrEmpty(output, string.Format("Expected test case {0} to be not null or empty.", counter));
            Assert.AreEqual(code, output, string.Format("Expected test case {0} to ensure that the generated code and validated code match.", counter));

            // assert no bad words
            var parts = output.Split('-');
            var contains = badWords.Any(part => parts.Any(item => part.ToUpperInvariant().Contains(item.ToUpperInvariant())));
            Assert.IsFalse(contains, string.Format("Expected test case {0} to contain no bad words.", counter));
        }
        /// <summary>
        /// The validate.
        /// </summary>
        /// <param name="code">The code.</param>
        /// <param name="opts">The opts.</param>
        /// <returns>
        /// The <see cref="string" />.
        /// </returns>
        /// <exception cref="System.Exception">Provide a code to be validated</exception>
        /// <exception cref="Exception"></exception>
        public string Validate(string code, Options opts)
        {
            if (string.IsNullOrEmpty(code))
            {
                throw new Exception("Provide a code to be validated");
            }

            // uppercase the code, replace OIZS with 0125
            code = new string(Array.FindAll(code.ToCharArray(), char.IsLetterOrDigit))
                .ToUpper()
                .Replace("O", "0")
                .Replace("I", "1")
                .Replace("Z", "2")
                .Replace("S", "5");

            // split in the different parts
            var parts = new List<string>();
            var tmp = code;
            while (tmp.Length > 0)
            {
                parts.Add(tmp.Substring(0, opts.PartLength));
                tmp = tmp.Substring(opts.PartLength);
            }

            // make sure we have been given the same number of parts as we are expecting
            if (parts.Count != opts.Parts)
            {
                return string.Empty;
            }

            // validate each part
            for (var i = 0; i < parts.Count; i++)
            {
                var part = parts[i];

                // check this part has 4 chars
                if (part.Length != opts.PartLength)
                {
                    return string.Empty;
                }

                // split out the data and the check
                var data = part.Substring(0, opts.PartLength - 1);
                var check = part.Substring(opts.PartLength - 1, 1);

                if (Convert.ToChar(check) != this.CheckDigitAlg1(data, i + 1))
                {
                    return string.Empty;
                }
            }

            // everything looked ok with this code
            return string.Join("-", parts.ToArray());
        }
        /// <summary>
        /// The generate.
        /// </summary>
        /// <param name="opts">
        /// The opts.
        /// </param>
        /// <returns>
        /// The <see cref="string"/>.
        /// </returns>
        public string Generate(Options opts)
        {
            var parts = new List<string>();

            // if  plaintext wasn't set then override
            if (string.IsNullOrEmpty(opts.Plaintext))
            {
                // not yet implemented
                opts.Plaintext = this.GetRandomPlaintext(8);
            }

            // generate parts and combine
            do
            {
                for (var i = 0; i < opts.Parts; i++)
                {
                    var sb = new StringBuilder();
                    for (var j = 0; j < opts.PartLength - 1; j++)
                    {
                        sb.Append(this.GetRandomSymbol());
                    }

                    var part = sb.ToString();
                    sb.Append(this.CheckDigitAlg1(part, i + 1));
                    parts.Add(sb.ToString());
                }
            }
            while (this.ContainsBadWord(string.Join(string.Empty, parts.ToArray())));

            return string.Join("-", parts.ToArray());
        }