Ejemplo n.º 1
0
        public void FileWithUnknownColumns_ShouldDiscardColumns()
        {
            var description = new CsvMetaData
            {
                SeparatorChar           = ',',
                FirstLineHasColumnNames = true,
                IgnoreUnknownColumns    = true,
            };

            //The following input has 5 columns: Id | Name | Last Name | Age | City. Only the Name, Last Name and Age will be read.

            string input =
                @"Id,Name,Last Name,Age,City
1,John,Doe,15,Washington
2,Jane,Doe,20,New York
";
            var expected = new[]
            {
                new Person
                {
                    Name     = "John",
                    LastName = "Doe",
                    Age      = 15
                },
                new Person
                {
                    Name     = "Jane",
                    LastName = "Doe",
                    Age      = 20
                },
            };

            AssertRead(input, description, expected);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Executes a Read and tests whether it outputs the expected records.
        /// </summary>
        /// <typeparam name="T">
        /// Type of the output elements.
        /// </typeparam>
        /// <param name="testInput">
        /// String representing the contents of the file or StreamReader. This string is fed to the Read method
        /// as though it came from a file or StreamReader.
        /// </param>
        /// <param name="metaData">
        /// Passed to Read.
        /// </param>
        /// <param name="expected">
        /// Expected output.
        /// </param>
        public void AssertRead <T>(string testInput, CsvMetaData metaData, IEnumerable <T> expected)
            where T : class, IAssertable <T>, new()
        {
            IEnumerable <T> actual = TestRead <T>(testInput, metaData);

            AssertCollectionsEqual <T>(actual, expected);
        }
Ejemplo n.º 3
0
        public void GoodFileNoSeparatorCharUsEnglish()
        {
            // Arrange

            var fileDescriptionNamesUs = new CsvMetaData
            {
                NoSeparatorChar = true,
                UseOutputFormatForParsingCsvValue = false,
                FirstLineHasColumnNames           = false,
                EnforceCsvColumnAttribute         = true, // default is false
                FileCultureName = "en-US"                 // default is the current culture
            };

            string testInput =
                @"AAAAAAAA34.18405/23/08\n
BBBBBBBB10.31105/12/12\n
CCCCCCCC12.00012/23/08";

            var expected = new[] {
                new ProductDataCharLength {
                    name = "AAAAAAAA", weight = 34.184, startDate = new DateTime(2008, 5, 23),
                },
                new ProductDataCharLength {
                    name = "BBBBBBBB", weight = 10.311, startDate = new DateTime(2012, 5, 12),
                },
                new ProductDataCharLength {
                    name = "CCCCCCCC", weight = 12.000, startDate = new DateTime(2008, 12, 23),
                }
            };

            // Act and Assert

            AssertRead(testInput, fileDescriptionNamesUs, expected);
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Used to test the Write method
        /// </summary>
        /// <typeparam name="T">
        /// The type of the input elements.
        /// </typeparam>
        /// <param name="values">
        /// The collection of input elements.
        /// </param>
        /// <param name="metaData">
        /// Passed directly to write.
        /// </param>
        /// <returns>
        /// Returns a string with the content that the Write method writes to a file or TextWriter.
        /// </returns>
        public string TestWrite <T>(IEnumerable <T> values, CsvMetaData metaData) where T : class
        {
            TextWriter stream = new StringWriter();
            CsvContext cc     = new CsvContext();

            cc.Write(values, stream, metaData);
            return(stream.ToString());
        }
Ejemplo n.º 5
0
        public void GoodFileCommaDelimitedWithTrailingSeparatorChars()
        {
            // Arrange

            CsvMetaData metaDataNamesUs = new CsvMetaData
            {
                SeparatorChar               = ',',     // default is ','
                FirstLineHasColumnNames     = true,
                EnforceCsvColumnAttribute   = false,   // default is false
                FileCultureName             = "en-US", // default is the current culture
                IgnoreTrailingSeparatorChar = true
            };

            string testInput =
                @"name,        weight,       startDate, launchTime,               nbrAvailable,onsale,shopsAvailable,    code,  price,    description,
moonbuggy,   34.184,       5/23/08,   5-May-2009 4:11 pm,       1205,        true,  ""Paris, New York"", 1F,    $540.12,  newly launched product,
""mouse trap"",45E-5,        1/2/1985,  ""7 August 1988, 0:00 am"", ""4,030"",     FALSE, ""This field has
a newline"", 100, ""$78,300"", ""This field has quotes(""""), and
two newlines
and a quoted """"string""""""
dog house,    ""45,230,990"",29 Feb 2004, ,                  -56,        True,"""",                  FF10, ""12,008"",";

            var expected = new[] {
                new ProductData {
                    name         = "moonbuggy", weight = 34.184, startDate = new DateTime(2008, 5, 23), launchTime = new DateTime(2009, 5, 5, 16, 11, 0),
                    nbrAvailable = 1205, onsale = true, shopsAvailable = "Paris, New York", hexProductCode = 31, retailPrice = 540.12M,
                    description  = "newly launched product"
                },
                new ProductData {
                    name         = "mouse trap", weight = 45E-5, startDate = new DateTime(1985, 1, 2), launchTime = new DateTime(1988, 8, 7, 0, 0, 0),
                    nbrAvailable = 4030, onsale = false, shopsAvailable = @"This field has
a newline", hexProductCode = 256, retailPrice = 78300M,
                    description  = @"This field has quotes(""), and
two newlines
and a quoted ""string"""
                },
                new ProductData {
                    name         = "dog house", weight = 45230990, startDate = new DateTime(2004, 2, 29), launchTime = default(DateTime),
                    nbrAvailable = -56, onsale = true, shopsAvailable = "", hexProductCode = 65296, retailPrice = 12008M,
                    description  = null
                }
            };

            // Act and Assert

            AssertRead(testInput, metaDataNamesUs, expected);
        }
Ejemplo n.º 6
0
        public void GoodFileUsingOutputFormatForParsingDatesCharUsEnglish()
        {
            // Arrange

            var fileDescriptionNamesUs = new CsvMetaData
            {
                SeparatorChar                     = ';',
                FirstLineHasColumnNames           = false,
                UseOutputFormatForParsingCsvValue = true,
                EnforceCsvColumnAttribute         = true,   // default is false
                FileCultureName                   = "en-US" // default is the current culture
            };

            StringBuilder input = new StringBuilder();

            input.Append("AAAAAAAA;052308");
            input.Append(Environment.NewLine);
            input.Append("BBBBBBBB;051212");
            input.Append(Environment.NewLine);
            input.Append(Environment.NewLine);
            input.Append("CCCCCCCC;122308");



            var expected = new[] {
                new ProductDataParsingOutputFormat {
                    name = "AAAAAAAA", startDate = new DateTime(2008, 5, 23),
                },
                new ProductDataParsingOutputFormat {
                    name = "BBBBBBBB", startDate = new DateTime(2012, 5, 12),
                },
                new ProductDataParsingOutputFormat {
                    name = "CCCCCCCC", startDate = new DateTime(2008, 12, 23),
                }
            };

            // Act and Assert

            AssertRead(input.ToString(), fileDescriptionNamesUs, expected);
        }
Ejemplo n.º 7
0
        public void GoodFileTabDelimitedNoNamesInFirstLineNLnl()
        {
            // Arrange

            CsvMetaData metaDataNonamesNl = new CsvMetaData
            {
                SeparatorChar             = '\t', // tab character
                FirstLineHasColumnNames   = false,
                EnforceCsvColumnAttribute = true,
                FileCultureName           = "nl-NL" // default is the current culture
            };

            string testInput =
                "moonbuggy\t       23/5/08\t   5-Mei-2009 16:11 pm\t   34.184\t  \"Paris, New York\"\t 1F\t    €540,12\t        true\t  newly launched product\r\n\"mouse trap\"\t        2/1/1985\t  \"7 Augustus 1988\t 0:00\"\t45E-5\t \"This field has\r\na newline\"\t 100\t \"€78.300\"\t     FALSE\t \"This field has quotes(\"\"), and\r\ntwo newlines\r\nand a quoted \"\"string\"\"\"\r\ndog house\t29 Feb 2004\t \t    \"45.230.990\"\t\"\"\t                  FF10\t \"12.008\"\t        True";
            var expected = new[] {
                new ProductData {
                    name         = "moonbuggy", weight = 34184, startDate = new DateTime(2008, 5, 23), launchTime = new DateTime(2009, 5, 5, 16, 11, 0),
                    nbrAvailable = 0, onsale = true, shopsAvailable = "Paris, New York", hexProductCode = 31, retailPrice = 540.12M,
                    description  = "newly launched product"
                },
                new ProductData {
                    name         = "mouse trap", weight = 45E-5, startDate = new DateTime(1985, 1, 2), launchTime = new DateTime(1988, 8, 7, 0, 0, 0),
                    nbrAvailable = 0, onsale = false, shopsAvailable = @"This field has
a newline", hexProductCode = 256, retailPrice = 78300M,
                    description  = @"This field has quotes(""), and
two newlines
and a quoted ""string"""
                },
                new ProductData {
                    name         = "dog house", weight = 45230990, startDate = new DateTime(2004, 2, 29), launchTime = default(DateTime),
                    nbrAvailable = 0, onsale = true, shopsAvailable = "", hexProductCode = 65296, retailPrice = 12008M,
                    description  = null
                }
            };

            // Act and Assert

            AssertRead(testInput, metaDataNonamesNl, expected);
        }
Ejemplo n.º 8
0
        public void GoodFileCommaDelimitedUseFieldIndexForReadingDataCharUseOutputFormatForParsingUSEnglish()
        {
            // Arrange

            CsvMetaData metaDataNamesUs = new CsvMetaData
            {
                SeparatorChar        = ',',
                IgnoreUnknownColumns = true,
                UseOutputFormatForParsingCsvValue = true,

                UseFieldIndexForReadingData = true,
                FirstLineHasColumnNames     = false,
                EnforceCsvColumnAttribute   = true,   // default is false
                FileCultureName             = "en-US" // default is the current culture
            };

            string testInput =
                "AAAAAAAA,__,34.184,05/23/08" + Environment.NewLine +
                "BBBBBBBB,__,10.311,05/12/12" + Environment.NewLine +
                "CCCCCCCC,__,12.000,12/23/08";

            var expected = new[] {
                new ProductDataSpecificFieldIndex()
                {
                    name = "AAAAAAAA", weight = 34.184, startDate = new DateTime(2008, 5, 23),
                },
                new ProductDataSpecificFieldIndex {
                    name = "BBBBBBBB", weight = 10.311, startDate = new DateTime(2012, 5, 12),
                },
                new ProductDataSpecificFieldIndex {
                    name = "CCCCCCCC", weight = 12.000, startDate = new DateTime(2008, 12, 23),
                }
            };

            // Act and Assert

            AssertRead(testInput, metaDataNamesUs, expected);
        }
Ejemplo n.º 9
0
        public void GoodFileCommaDelimitedNamesInFirstLineNLnl()
        {
            // Arrange

            List <ProductData> dataRows_Test = new List <ProductData>();

            dataRows_Test.Add(new ProductData {
                retailPrice = 4.59M, name = "Wooden toy", startDate = new DateTime(2008, 2, 1), nbrAvailable = 67
            });
            dataRows_Test.Add(new ProductData {
                onsale = true, weight = 4.03, shopsAvailable = "Ashfield", description = ""
            });
            dataRows_Test.Add(new ProductData {
                name = "Metal box", launchTime = new DateTime(2009, 11, 5, 4, 50, 0), description = "Great\nproduct"
            });

            CsvMetaData metaDataNamesNl2 = new CsvMetaData
            {
                SeparatorChar             = ',',
                FirstLineHasColumnNames   = true,
                EnforceCsvColumnAttribute = false,
                TextEncoding    = Encoding.Unicode,
                FileCultureName = "nl-Nl" // default is the current culture
            };

            string expected =
                @"name,startDate,launchTime,weight,shopsAvailable,code,price,onsale,description,nbrAvailable,unusedField
Wooden toy,1-2-2008,01 jan 00:00:00,""000,000"",,0,""€ 4,59"",False,,67,
,1-1-0001,01 jan 00:00:00,""004,030"",Ashfield,0,""€ 0,00"",True,"""",0,
Metal box,1-1-0001,05 nov 04:50:00,""000,000"",,0,""€ 0,00"",False,""Great
product"",0,
";

            // Act and Assert

            AssertWrite(dataRows_Test, metaDataNamesNl2, expected);
        }
Ejemplo n.º 10
0
        /// <summary>
        /// Used to test the Read method.
        /// </summary>
        /// <typeparam name="T">
        /// Type of the output elements.
        /// </typeparam>
        /// <param name="testInput">
        /// String representing the contents of the file or StreamReader. This string is fed to the Read method
        /// as though it came from a file or StreamReader.
        /// </param>
        /// <param name="metaData">
        /// Passed to Read.
        /// </param>
        /// <returns>
        /// Output of Read.
        /// </returns>
        public IEnumerable <T> TestRead <T>(string testInput, CsvMetaData metaData) where T : class, new()
        {
            CsvContext cc = new CsvContext();

            return(cc.Read <T>(StreamReaderFromString(testInput), metaData));
        }
Ejemplo n.º 11
0
        /// <summary>
        /// Executes a Write and tests whether it outputs the expected records.
        /// </summary>
        /// <typeparam name="T">
        /// The type of the input elements.
        /// </typeparam>
        /// <param name="values">
        /// The collection of input elements.
        /// </param>
        /// <param name="metaData">
        /// Passed directly to write.
        /// </param>
        /// <param name="expected">
        /// Expected output.
        /// </param>
        public void AssertWrite <T>(IEnumerable <T> values, CsvMetaData metaData, string expected) where T : class
        {
            string actual = TestWrite <T>(values, metaData);

            Assert.Equal(Utils.NormalizeString(actual), Utils.NormalizeString(expected));
        }
Ejemplo n.º 12
0
        static void Main(string[] args)
        {
            // ------------------------------------
            // Reading files, no erros
            // The input files are meant to test the library code, so have lots of weird cases.

            // ----
            // Read comma delimited file with names in first line, US-English culture.
            // Fields do not have to have CsvColumn attribute.

            CsvContext cc = new CsvContext();

            IEnumerable <ProductData_MissingFieldIndex> dataRows_namesUs = null;
            IEnumerable <TestDataRow> dataRows_namesUsRaw = null;
            CsvMetaData metaDataNamesUs = new CsvMetaData
            {
                SeparatorChar             = ',',    // default is ','
                FirstLineHasColumnNames   = true,
                EnforceCsvColumnAttribute = false,  // default is false
                FileCultureName           = "en-US" // default is the current culture
            };

            try
            {
                dataRows_namesUs =
                    cc.Read <ProductData>("TestFiles/goodfile_us.csv", metaDataNamesUs) as IEnumerable <ProductData_MissingFieldIndex>;

                Utils.OutputData <ProductData>(dataRows_namesUs, "Good file, English US culture");

                // -----------
                // Manually change contents of file, to see whether file is read again with new values.

                Utils.OutputData <ProductData>(dataRows_namesUs, "Good file, English US culture, second read");

                // ------------
                // Partial read - read just one record from the file

                foreach (ProductData_MissingFieldIndex row in dataRows_namesUs)
                {
                    break;
                }

                // -----------
                // Read raw data rows

                dataRows_namesUsRaw =
                    cc.Read <TestDataRow>("TestFiles/goodfile_us.csv", metaDataNamesUs) as IEnumerable <TestDataRow>;

                Utils.OutputData <TestDataRow>(dataRows_namesUsRaw, "Good file, English US culture, Raw data rows");
            }
            catch (Exception e)
            {
                Utils.OutputException(e);
            }

            // ----
            // Read file without names, Dutch culture, tab delimited.

            // EnforceCsvColumnAttribute is not set, because it is implicitly true
            // when there are no names in the first line. This is because only
            // fields that have a FieldIndex can be used, which means having
            // a CsvColumn attribute.

            CsvMetaData metaDataNonamesNl = new CsvMetaData
            {
                SeparatorChar             = '\t', // tab character
                FirstLineHasColumnNames   = false,
                EnforceCsvColumnAttribute = true,
                FileCultureName           = "nl-NL" // default is the current culture
            };

            try
            {
                var dataRowsNonamesNl =
                    cc.Read <ProductData>("TestFiles/goodfile_nl.csv", metaDataNonamesNl);

                Utils.OutputData <ProductData>(dataRowsNonamesNl, "Good file, Dutch culture");
            }
            catch (Exception e)
            {
                Utils.OutputException(e);
            }

            // ----
            // Read a stream instead of a file, without names, Dutch culture, tab delimited.

            // EnforceCsvColumnAttribute is not set, because it is implicitly true
            // when there are no names in the first line. This is because only
            // fields that have a FieldIndex can be used, which means having
            // a CsvColumn attribute.

            CsvMetaData metaDataNonamesNlStream = new CsvMetaData
            {
                SeparatorChar             = '\t', // tab character
                FirstLineHasColumnNames   = false,
                EnforceCsvColumnAttribute = true,
                FileCultureName           = "nl-NL" // default is the current culture
            };

            try
            {
                using (StreamReader sr =
                           new StreamReader("TestFiles/goodfile_nl.csv", Encoding.UTF8))
                {
                    var dataRowsNonamesNl =
                        cc.Read <ProductData>(sr, metaDataNonamesNlStream);

                    Utils.OutputData(dataRowsNonamesNl, "Good file, Dutch culture, using stream");
                }
            }
            catch (Exception e)
            {
                Utils.OutputException(e);
            }

            // ------------------------------------
            // Reading files, with errors

            // Type has duplicate FileIndices

            try
            {
                IEnumerable <ProductData_DuplicateIndices> dataRows2 =
                    cc.Read <ProductData_DuplicateIndices>("TestFiles/goodfile_nl.csv", metaDataNonamesNl);

                Utils.OutputData(dataRows2, "Good file, Dutch culture");
            }
            catch (Exception e)
            {
                Utils.OutputException(e);
            }

            // Type has required fields that do not have a FieldIndex.

            try
            {
                IEnumerable <ProductData_MissingFieldIndex> dataRows2 =
                    cc.Read <ProductData_MissingFieldIndex>("TestFiles/goodfile_nl.csv", metaDataNonamesNl);

                Utils.OutputData <ProductData_MissingFieldIndex>(dataRows2, "Good file, Dutch culture");
            }
            catch (Exception e)
            {
                Utils.OutputException(e);
            }

            // CsvFileDescription.EnforceCsvColumnAttribute is false, but needs to be true because
            // CsvFileDescription.FirstLineHasColumnNames is false.

            CsvMetaData metaDataBad = new CsvMetaData
            {
                SeparatorChar             = '\t', // tab character
                FirstLineHasColumnNames   = false,
                EnforceCsvColumnAttribute = false,
                FileCultureName           = "nl-NL" // default is the current culture
            };

            try
            {
                IEnumerable <ProductData> dataRows_nonamesNl_bad =
                    cc.Read <ProductData>("TestFiles/goodfile_nl.csv", metaDataBad);

                Utils.OutputData <ProductData>(dataRows_nonamesNl_bad, "Good file, Dutch culture");
            }
            catch (Exception e)
            {
                Utils.OutputException(e);
            }

            // ----
            // Read file with names, but one name not declared in type

            try
            {
                IEnumerable <ProductData> dataRows_namesUs_3 =
                    cc.Read <ProductData>("TestFiles/badfile_unknownname.csv", metaDataNamesUs);

                Utils.OutputData <ProductData>(dataRows_namesUs_3, "Bad file, English US culture, unknown name");
            }
            catch (Exception e)
            {
                Utils.OutputException(e);
            }


            // ----
            // Read file with names, only columns with CsvColumn attribute participate.
            // But one name matches a column without CsvColumn attribute.

            var fileDescriptionNamesUsEnforceCsvColumn = new CsvMetaData
            {
                SeparatorChar             = ',',    // default is ','
                FirstLineHasColumnNames   = true,
                EnforceCsvColumnAttribute = true,   // default is false
                FileCultureName           = "en-US" // default is the current culture
            };

            try
            {
                var dataRowsNamesUs2 =
                    cc.Read <ProductData>("TestFiles/goodfile_us.csv", fileDescriptionNamesUsEnforceCsvColumn);

                Utils.OutputData(dataRowsNamesUs2, "Good file, English US culture");
            }
            catch (Exception e)
            {
                Utils.OutputException(e);
            }


            // ----
            // Various errors in data fields - all captured in AggregatedException
            // * A row with too many fields
            // * Rows with badly formatted data - letters in numeric fields, bad dates

            CsvMetaData metaDataNonamesUs = new CsvMetaData
            {
                SeparatorChar             = ',', // default is ','
                FirstLineHasColumnNames   = true,
                EnforceCsvColumnAttribute = true,
                FileCultureName           = "en-US" // default is the current culture
            };

            try
            {
                var dataRowsNamesUsDataerrors =
                    cc.Read <ProductData>("TestFiles/badfile_us_dataerrors.csv", metaDataNonamesUs);

                Utils.OutputData(
                    dataRowsNamesUsDataerrors,
                    "Bad file, English US culture, various data errors");
            }
            catch (Exception e)
            {
                Utils.OutputException(e);
            }


            // ------------------------------------
            // Writing files

            // ---------------
            // Create own IEnumarable, rather then using one created by reading a file.
            // Dutch, names in first line, don't limit writing to fields with CsvColumn attribute.

            var dataRowsTest = new List <ProductData>();

            dataRowsTest.Add(new ProductData {
                retailPrice = 4.59M, name = "Wooden toy", startDate = DateTime.Parse("1/2/2008"), nbrAvailable = 67
            });
            dataRowsTest.Add(new ProductData {
                onsale = true, weight = 4.03, shopsAvailable = "Ashfield", description = ""
            });
            dataRowsTest.Add(new ProductData {
                name = "Metal box", launchTime = DateTime.Parse("5/11/2009 4:50"), description = "Great\nproduct"
            });

            var fileDescriptionNamesNl2 = new CsvMetaData
            {
                SeparatorChar             = ',',
                FirstLineHasColumnNames   = true,
                EnforceCsvColumnAttribute = false,
                TextEncoding    = Encoding.Unicode,
                FileCultureName = "nl-Nl" // default is the current culture
            };

            try
            {
                cc.Write(
                    dataRowsTest,
                    "TestFiles/output_newdata_names_nl.csv",
                    fileDescriptionNamesNl2);
            }
            catch (Exception e)
            {
                Utils.OutputException(e);
            }

            // ---------------
            // Write tab delimited file, US-English, no names in first line
            // using FieldIndices provided in CsvColumn attributes

            var fileDescription_nonamesUs_output = new CsvMetaData
            {
                SeparatorChar             = '\t',
                FirstLineHasColumnNames   = false,
                EnforceCsvColumnAttribute = true,
                FileCultureName           = "en-US" // default is the current culture
            };

            try
            {
                cc.Write <ProductData>(
                    dataRows_namesUs,
                    "TestFiles/output_nonames_us.csv",
                    fileDescription_nonamesUs_output);
            }
            catch (Exception e)
            {
                Utils.OutputException(e);
            }

            // ---------------
            // Write comma delimited file, Dutch, names in first line using
            // CsvColumn attributes

            var fileDescriptionNamesNl = new CsvMetaData
            {
                SeparatorChar             = ',',
                FirstLineHasColumnNames   = true,
                EnforceCsvColumnAttribute = true,
                TextEncoding    = Encoding.Unicode,
                FileCultureName = "nl-NL" // default is the current culture
            };

            try
            {
                cc.Write <ProductData>(
                    dataRows_namesUs,
                    "TestFiles/output_names_nl.csv",
                    fileDescriptionNamesNl);
            }
            catch (Exception e)
            {
                Utils.OutputException(e);
            }


            // Write comma delimited file, column names in first record,
            // using anonymous type. Because there are no FieldIndices,
            // the order of the fields on each line in the file is not guaranteed.
            //
            // FileCultureName is not set, so the current culture is used
            // (so if you are Canadian, the system uses Canadian dates, etc.)

            var fileDescriptionAnon = new CsvMetaData
            {
                SeparatorChar             = ',',
                FirstLineHasColumnNames   = true,
                EnforceCsvColumnAttribute = false
                                            // use current culture
            };

            try
            {
                var query = from row in dataRows_namesUs
                            orderby row.weight
                            select new {
                    ProductName = row.name,
                    InShops     = row.startDate,
                    Markup      = row.retailPrice * (decimal)0.5
                };

                cc.Write(
                    query,
                    "TestFiles/output_anon.csv",
                    fileDescriptionAnon);
            }
            catch (Exception e)
            {
                Utils.OutputException(e);
            }

            // ------------------------------------
            // Writing files, with errors

            // If not writing field names to the first line, then you have to only
            // use fields with the CsvColumn attribute, and give them all a FieldIndex.
            // Otherwise, there is no reliable way to read back the data, because the order
            // of the fields is not guaranteed.

            try
            {
                cc.Write <ProductData>(
                    dataRows_namesUs,
                    "TestFiles/output_bad.csv",
                    metaDataBad);
            }
            catch (Exception e)
            {
                Utils.OutputException(e);
            }


            // CsvFileDescription settings are good, but not all fields with CsvColumn attribute
            // have a FieldIndex.

            CsvMetaData metaDataNonamesNl2 = new CsvMetaData
            {
                SeparatorChar             = ',',
                FirstLineHasColumnNames   = false,
                EnforceCsvColumnAttribute = true,
                TextEncoding    = Encoding.Unicode,
                FileCultureName = "nl-NL" // default is the current culture
            };

            try
            {
                List <ProductData_MissingFieldIndex> emptyData = new List <ProductData_MissingFieldIndex>();

                cc.Write <ProductData_MissingFieldIndex>(
                    emptyData,
                    "TestFiles/output_bad.csv",
                    metaDataNonamesNl2);
            }
            catch (Exception e)
            {
                Utils.OutputException(e);
            }
        }