├── .gitignore ├── CSwiftV.podspec ├── CSwiftV.xcodeproj ├── CSwiftVTests_Info.plist ├── CSwiftV_Info.plist ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ └── WorkspaceSettings.xcsettings └── xcshareddata │ └── xcschemes │ └── CSwiftV-Package.xcscheme ├── LICENSE ├── Package.swift ├── README.md ├── Sources └── CSwiftV │ └── CSwiftV.swift └── Tests ├── CSwiftVTests ├── CSwiftVTests.swift └── XCTestManifests.swift └── LinuxMain.swift /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 3 | ## Build generated 4 | build/ 5 | DerivedData 6 | 7 | ## Various settings 8 | *.pbxuser 9 | !default.pbxuser 10 | *.mode1v3 11 | !default.mode1v3 12 | *.mode2v3 13 | !default.mode2v3 14 | *.perspectivev3 15 | !default.perspectivev3 16 | xcuserdata 17 | 18 | ## Other 19 | *.xccheckout 20 | *.moved-aside 21 | *.xcuserstate 22 | *.xcscmblueprint 23 | 24 | ## Obj-C/Swift specific 25 | *.hmap 26 | *.ipa 27 | 28 | ## Swift Package Manager 29 | .build 30 | -------------------------------------------------------------------------------- /CSwiftV.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | 3 | s.name = "CSwiftV" 4 | s.version = "0.0.9" 5 | s.summary = "A swift CSV parser" 6 | 7 | s.description = <<-DESC 8 | A csv parser conforming (and tested as much) to [rfc4180](http://tools.ietf.org/html/rfc4180#section-2) i.e the closest thing to a csv spec. 9 | DESC 10 | 11 | s.homepage = "https://github.com/daniel1of1/CSwiftV" 12 | 13 | s.license = "MIT" 14 | 15 | s.author = { "Daniel Haight" => "other@haight.io" } 16 | s.social_media_url = "http://twitter.com/daniel1of1" 17 | 18 | s.ios.deployment_target = "8.0" 19 | s.osx.deployment_target = "10.9" 20 | s.swift_version = '5.0' 21 | 22 | s.source = { :git => "https://github.com/daniel1of1/CSwiftV.git", :tag => s.version } 23 | 24 | s.source_files = "Sources/CSwiftV.swift" 25 | 26 | s.requires_arc = true 27 | 28 | end 29 | -------------------------------------------------------------------------------- /CSwiftV.xcodeproj/CSwiftVTests_Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | CFBundleDevelopmentRegion 5 | en 6 | CFBundleExecutable 7 | $(EXECUTABLE_NAME) 8 | CFBundleIdentifier 9 | $(PRODUCT_BUNDLE_IDENTIFIER) 10 | CFBundleInfoDictionaryVersion 11 | 6.0 12 | CFBundleName 13 | $(PRODUCT_NAME) 14 | CFBundlePackageType 15 | BNDL 16 | CFBundleShortVersionString 17 | 1.0 18 | CFBundleSignature 19 | ???? 20 | CFBundleVersion 21 | $(CURRENT_PROJECT_VERSION) 22 | NSPrincipalClass 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /CSwiftV.xcodeproj/CSwiftV_Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | CFBundleDevelopmentRegion 5 | en 6 | CFBundleExecutable 7 | $(EXECUTABLE_NAME) 8 | CFBundleIdentifier 9 | $(PRODUCT_BUNDLE_IDENTIFIER) 10 | CFBundleInfoDictionaryVersion 11 | 6.0 12 | CFBundleName 13 | $(PRODUCT_NAME) 14 | CFBundlePackageType 15 | FMWK 16 | CFBundleShortVersionString 17 | 1.0 18 | CFBundleSignature 19 | ???? 20 | CFBundleVersion 21 | $(CURRENT_PROJECT_VERSION) 22 | NSPrincipalClass 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /CSwiftV.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = "1"; 4 | objectVersion = "46"; 5 | objects = { 6 | "CSwiftV::CSwiftV" = { 7 | isa = "PBXNativeTarget"; 8 | buildConfigurationList = "OBJ_20"; 9 | buildPhases = ( 10 | "OBJ_23", 11 | "OBJ_25" 12 | ); 13 | dependencies = ( 14 | ); 15 | name = "CSwiftV"; 16 | productName = "CSwiftV"; 17 | productReference = "CSwiftV::CSwiftV::Product"; 18 | productType = "com.apple.product-type.framework"; 19 | }; 20 | "CSwiftV::CSwiftV::Product" = { 21 | isa = "PBXFileReference"; 22 | path = "CSwiftV.framework"; 23 | sourceTree = "BUILT_PRODUCTS_DIR"; 24 | }; 25 | "CSwiftV::CSwiftVPackageTests::ProductTarget" = { 26 | isa = "PBXAggregateTarget"; 27 | buildConfigurationList = "OBJ_33"; 28 | buildPhases = ( 29 | ); 30 | dependencies = ( 31 | "OBJ_36" 32 | ); 33 | name = "CSwiftVPackageTests"; 34 | productName = "CSwiftVPackageTests"; 35 | }; 36 | "CSwiftV::CSwiftVTests" = { 37 | isa = "PBXNativeTarget"; 38 | buildConfigurationList = "OBJ_38"; 39 | buildPhases = ( 40 | "OBJ_41", 41 | "OBJ_43" 42 | ); 43 | dependencies = ( 44 | "OBJ_45" 45 | ); 46 | name = "CSwiftVTests"; 47 | productName = "CSwiftVTests"; 48 | productReference = "CSwiftV::CSwiftVTests::Product"; 49 | productType = "com.apple.product-type.bundle.unit-test"; 50 | }; 51 | "CSwiftV::CSwiftVTests::Product" = { 52 | isa = "PBXFileReference"; 53 | path = "CSwiftVTests.xctest"; 54 | sourceTree = "BUILT_PRODUCTS_DIR"; 55 | }; 56 | "CSwiftV::SwiftPMPackageDescription" = { 57 | isa = "PBXNativeTarget"; 58 | buildConfigurationList = "OBJ_27"; 59 | buildPhases = ( 60 | "OBJ_30" 61 | ); 62 | dependencies = ( 63 | ); 64 | name = "CSwiftVPackageDescription"; 65 | productName = "CSwiftVPackageDescription"; 66 | productType = "com.apple.product-type.framework"; 67 | }; 68 | "OBJ_1" = { 69 | isa = "PBXProject"; 70 | attributes = { 71 | LastSwiftMigration = "9999"; 72 | LastUpgradeCheck = "9999"; 73 | }; 74 | buildConfigurationList = "OBJ_2"; 75 | compatibilityVersion = "Xcode 3.2"; 76 | developmentRegion = "English"; 77 | hasScannedForEncodings = "0"; 78 | knownRegions = ( 79 | "en" 80 | ); 81 | mainGroup = "OBJ_5"; 82 | productRefGroup = "OBJ_13"; 83 | projectDirPath = "."; 84 | targets = ( 85 | "CSwiftV::CSwiftV", 86 | "CSwiftV::SwiftPMPackageDescription", 87 | "CSwiftV::CSwiftVPackageTests::ProductTarget", 88 | "CSwiftV::CSwiftVTests" 89 | ); 90 | }; 91 | "OBJ_10" = { 92 | isa = "PBXGroup"; 93 | children = ( 94 | "OBJ_11" 95 | ); 96 | name = "Tests"; 97 | path = ""; 98 | sourceTree = "SOURCE_ROOT"; 99 | }; 100 | "OBJ_11" = { 101 | isa = "PBXGroup"; 102 | children = ( 103 | "OBJ_12" 104 | ); 105 | name = "CSwiftVTests"; 106 | path = "Tests/CSwiftVTests"; 107 | sourceTree = "SOURCE_ROOT"; 108 | }; 109 | "OBJ_12" = { 110 | isa = "PBXFileReference"; 111 | path = "CSwiftVTests.swift"; 112 | sourceTree = ""; 113 | }; 114 | "OBJ_13" = { 115 | isa = "PBXGroup"; 116 | children = ( 117 | "CSwiftV::CSwiftV::Product", 118 | "CSwiftV::CSwiftVTests::Product" 119 | ); 120 | name = "Products"; 121 | path = ""; 122 | sourceTree = "BUILT_PRODUCTS_DIR"; 123 | }; 124 | "OBJ_16" = { 125 | isa = "PBXFileReference"; 126 | path = "LICENSE"; 127 | sourceTree = ""; 128 | }; 129 | "OBJ_17" = { 130 | isa = "PBXFileReference"; 131 | path = "CSwiftV.podspec"; 132 | sourceTree = ""; 133 | }; 134 | "OBJ_18" = { 135 | isa = "PBXFileReference"; 136 | path = "README.md"; 137 | sourceTree = ""; 138 | }; 139 | "OBJ_2" = { 140 | isa = "XCConfigurationList"; 141 | buildConfigurations = ( 142 | "OBJ_3", 143 | "OBJ_4" 144 | ); 145 | defaultConfigurationIsVisible = "0"; 146 | defaultConfigurationName = "Release"; 147 | }; 148 | "OBJ_20" = { 149 | isa = "XCConfigurationList"; 150 | buildConfigurations = ( 151 | "OBJ_21", 152 | "OBJ_22" 153 | ); 154 | defaultConfigurationIsVisible = "0"; 155 | defaultConfigurationName = "Release"; 156 | }; 157 | "OBJ_21" = { 158 | isa = "XCBuildConfiguration"; 159 | buildSettings = { 160 | ENABLE_TESTABILITY = "YES"; 161 | FRAMEWORK_SEARCH_PATHS = ( 162 | "$(inherited)", 163 | "$(PLATFORM_DIR)/Developer/Library/Frameworks" 164 | ); 165 | HEADER_SEARCH_PATHS = ( 166 | "$(inherited)" 167 | ); 168 | INFOPLIST_FILE = "CSwiftV.xcodeproj/CSwiftV_Info.plist"; 169 | IPHONEOS_DEPLOYMENT_TARGET = "8.0"; 170 | LD_RUNPATH_SEARCH_PATHS = ( 171 | "$(inherited)", 172 | "$(TOOLCHAIN_DIR)/usr/lib/swift/macosx" 173 | ); 174 | MACOSX_DEPLOYMENT_TARGET = "10.10"; 175 | OTHER_CFLAGS = ( 176 | "$(inherited)" 177 | ); 178 | OTHER_LDFLAGS = ( 179 | "$(inherited)" 180 | ); 181 | OTHER_SWIFT_FLAGS = ( 182 | "$(inherited)" 183 | ); 184 | PRODUCT_BUNDLE_IDENTIFIER = "CSwiftV"; 185 | PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)"; 186 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 187 | SKIP_INSTALL = "YES"; 188 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = ( 189 | "$(inherited)" 190 | ); 191 | SWIFT_VERSION = "5.0"; 192 | TARGET_NAME = "CSwiftV"; 193 | TVOS_DEPLOYMENT_TARGET = "9.0"; 194 | WATCHOS_DEPLOYMENT_TARGET = "2.0"; 195 | }; 196 | name = "Debug"; 197 | }; 198 | "OBJ_22" = { 199 | isa = "XCBuildConfiguration"; 200 | buildSettings = { 201 | ENABLE_TESTABILITY = "YES"; 202 | FRAMEWORK_SEARCH_PATHS = ( 203 | "$(inherited)", 204 | "$(PLATFORM_DIR)/Developer/Library/Frameworks" 205 | ); 206 | HEADER_SEARCH_PATHS = ( 207 | "$(inherited)" 208 | ); 209 | INFOPLIST_FILE = "CSwiftV.xcodeproj/CSwiftV_Info.plist"; 210 | IPHONEOS_DEPLOYMENT_TARGET = "8.0"; 211 | LD_RUNPATH_SEARCH_PATHS = ( 212 | "$(inherited)", 213 | "$(TOOLCHAIN_DIR)/usr/lib/swift/macosx" 214 | ); 215 | MACOSX_DEPLOYMENT_TARGET = "10.10"; 216 | OTHER_CFLAGS = ( 217 | "$(inherited)" 218 | ); 219 | OTHER_LDFLAGS = ( 220 | "$(inherited)" 221 | ); 222 | OTHER_SWIFT_FLAGS = ( 223 | "$(inherited)" 224 | ); 225 | PRODUCT_BUNDLE_IDENTIFIER = "CSwiftV"; 226 | PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)"; 227 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 228 | SKIP_INSTALL = "YES"; 229 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = ( 230 | "$(inherited)" 231 | ); 232 | SWIFT_VERSION = "5.0"; 233 | TARGET_NAME = "CSwiftV"; 234 | TVOS_DEPLOYMENT_TARGET = "9.0"; 235 | WATCHOS_DEPLOYMENT_TARGET = "2.0"; 236 | }; 237 | name = "Release"; 238 | }; 239 | "OBJ_23" = { 240 | isa = "PBXSourcesBuildPhase"; 241 | files = ( 242 | "OBJ_24" 243 | ); 244 | }; 245 | "OBJ_24" = { 246 | isa = "PBXBuildFile"; 247 | fileRef = "OBJ_9"; 248 | }; 249 | "OBJ_25" = { 250 | isa = "PBXFrameworksBuildPhase"; 251 | files = ( 252 | ); 253 | }; 254 | "OBJ_27" = { 255 | isa = "XCConfigurationList"; 256 | buildConfigurations = ( 257 | "OBJ_28", 258 | "OBJ_29" 259 | ); 260 | defaultConfigurationIsVisible = "0"; 261 | defaultConfigurationName = "Release"; 262 | }; 263 | "OBJ_28" = { 264 | isa = "XCBuildConfiguration"; 265 | buildSettings = { 266 | LD = "/usr/bin/true"; 267 | OTHER_SWIFT_FLAGS = ( 268 | "-swift-version", 269 | "5", 270 | "-I", 271 | "$(TOOLCHAIN_DIR)/usr/lib/swift/pm/4_2", 272 | "-target", 273 | "x86_64-apple-macosx10.10", 274 | "-sdk", 275 | "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk" 276 | ); 277 | SWIFT_VERSION = "5.0"; 278 | }; 279 | name = "Debug"; 280 | }; 281 | "OBJ_29" = { 282 | isa = "XCBuildConfiguration"; 283 | buildSettings = { 284 | LD = "/usr/bin/true"; 285 | OTHER_SWIFT_FLAGS = ( 286 | "-swift-version", 287 | "5", 288 | "-I", 289 | "$(TOOLCHAIN_DIR)/usr/lib/swift/pm/4_2", 290 | "-target", 291 | "x86_64-apple-macosx10.10", 292 | "-sdk", 293 | "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk" 294 | ); 295 | SWIFT_VERSION = "5.0"; 296 | }; 297 | name = "Release"; 298 | }; 299 | "OBJ_3" = { 300 | isa = "XCBuildConfiguration"; 301 | buildSettings = { 302 | CLANG_ENABLE_OBJC_ARC = "YES"; 303 | COMBINE_HIDPI_IMAGES = "YES"; 304 | COPY_PHASE_STRIP = "NO"; 305 | DEBUG_INFORMATION_FORMAT = "dwarf"; 306 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 307 | ENABLE_NS_ASSERTIONS = "YES"; 308 | GCC_OPTIMIZATION_LEVEL = "0"; 309 | GCC_PREPROCESSOR_DEFINITIONS = ( 310 | "$(inherited)", 311 | "SWIFT_PACKAGE=1", 312 | "DEBUG=1" 313 | ); 314 | MACOSX_DEPLOYMENT_TARGET = "10.10"; 315 | ONLY_ACTIVE_ARCH = "YES"; 316 | OTHER_SWIFT_FLAGS = ( 317 | "-DXcode" 318 | ); 319 | PRODUCT_NAME = "$(TARGET_NAME)"; 320 | SDKROOT = "macosx"; 321 | SUPPORTED_PLATFORMS = ( 322 | "macosx", 323 | "iphoneos", 324 | "iphonesimulator", 325 | "appletvos", 326 | "appletvsimulator", 327 | "watchos", 328 | "watchsimulator" 329 | ); 330 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = ( 331 | "$(inherited)", 332 | "SWIFT_PACKAGE", 333 | "DEBUG" 334 | ); 335 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 336 | USE_HEADERMAP = "NO"; 337 | }; 338 | name = "Debug"; 339 | }; 340 | "OBJ_30" = { 341 | isa = "PBXSourcesBuildPhase"; 342 | files = ( 343 | "OBJ_31" 344 | ); 345 | }; 346 | "OBJ_31" = { 347 | isa = "PBXBuildFile"; 348 | fileRef = "OBJ_6"; 349 | }; 350 | "OBJ_33" = { 351 | isa = "XCConfigurationList"; 352 | buildConfigurations = ( 353 | "OBJ_34", 354 | "OBJ_35" 355 | ); 356 | defaultConfigurationIsVisible = "0"; 357 | defaultConfigurationName = "Release"; 358 | }; 359 | "OBJ_34" = { 360 | isa = "XCBuildConfiguration"; 361 | buildSettings = { 362 | }; 363 | name = "Debug"; 364 | }; 365 | "OBJ_35" = { 366 | isa = "XCBuildConfiguration"; 367 | buildSettings = { 368 | }; 369 | name = "Release"; 370 | }; 371 | "OBJ_36" = { 372 | isa = "PBXTargetDependency"; 373 | target = "CSwiftV::CSwiftVTests"; 374 | }; 375 | "OBJ_38" = { 376 | isa = "XCConfigurationList"; 377 | buildConfigurations = ( 378 | "OBJ_39", 379 | "OBJ_40" 380 | ); 381 | defaultConfigurationIsVisible = "0"; 382 | defaultConfigurationName = "Release"; 383 | }; 384 | "OBJ_39" = { 385 | isa = "XCBuildConfiguration"; 386 | buildSettings = { 387 | CLANG_ENABLE_MODULES = "YES"; 388 | EMBEDDED_CONTENT_CONTAINS_SWIFT = "YES"; 389 | FRAMEWORK_SEARCH_PATHS = ( 390 | "$(inherited)", 391 | "$(PLATFORM_DIR)/Developer/Library/Frameworks" 392 | ); 393 | HEADER_SEARCH_PATHS = ( 394 | "$(inherited)" 395 | ); 396 | INFOPLIST_FILE = "CSwiftV.xcodeproj/CSwiftVTests_Info.plist"; 397 | IPHONEOS_DEPLOYMENT_TARGET = "8.0"; 398 | LD_RUNPATH_SEARCH_PATHS = ( 399 | "$(inherited)", 400 | "@loader_path/../Frameworks", 401 | "@loader_path/Frameworks" 402 | ); 403 | MACOSX_DEPLOYMENT_TARGET = "10.10"; 404 | OTHER_CFLAGS = ( 405 | "$(inherited)" 406 | ); 407 | OTHER_LDFLAGS = ( 408 | "$(inherited)" 409 | ); 410 | OTHER_SWIFT_FLAGS = ( 411 | "$(inherited)" 412 | ); 413 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = ( 414 | "$(inherited)" 415 | ); 416 | SWIFT_VERSION = "5.0"; 417 | TARGET_NAME = "CSwiftVTests"; 418 | TVOS_DEPLOYMENT_TARGET = "9.0"; 419 | WATCHOS_DEPLOYMENT_TARGET = "2.0"; 420 | }; 421 | name = "Debug"; 422 | }; 423 | "OBJ_4" = { 424 | isa = "XCBuildConfiguration"; 425 | buildSettings = { 426 | CLANG_ENABLE_OBJC_ARC = "YES"; 427 | COMBINE_HIDPI_IMAGES = "YES"; 428 | COPY_PHASE_STRIP = "YES"; 429 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 430 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 431 | GCC_OPTIMIZATION_LEVEL = "s"; 432 | GCC_PREPROCESSOR_DEFINITIONS = ( 433 | "$(inherited)", 434 | "SWIFT_PACKAGE=1" 435 | ); 436 | MACOSX_DEPLOYMENT_TARGET = "10.10"; 437 | OTHER_SWIFT_FLAGS = ( 438 | "-DXcode" 439 | ); 440 | PRODUCT_NAME = "$(TARGET_NAME)"; 441 | SDKROOT = "macosx"; 442 | SUPPORTED_PLATFORMS = ( 443 | "macosx", 444 | "iphoneos", 445 | "iphonesimulator", 446 | "appletvos", 447 | "appletvsimulator", 448 | "watchos", 449 | "watchsimulator" 450 | ); 451 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = ( 452 | "$(inherited)", 453 | "SWIFT_PACKAGE" 454 | ); 455 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 456 | USE_HEADERMAP = "NO"; 457 | }; 458 | name = "Release"; 459 | }; 460 | "OBJ_40" = { 461 | isa = "XCBuildConfiguration"; 462 | buildSettings = { 463 | CLANG_ENABLE_MODULES = "YES"; 464 | EMBEDDED_CONTENT_CONTAINS_SWIFT = "YES"; 465 | FRAMEWORK_SEARCH_PATHS = ( 466 | "$(inherited)", 467 | "$(PLATFORM_DIR)/Developer/Library/Frameworks" 468 | ); 469 | HEADER_SEARCH_PATHS = ( 470 | "$(inherited)" 471 | ); 472 | INFOPLIST_FILE = "CSwiftV.xcodeproj/CSwiftVTests_Info.plist"; 473 | IPHONEOS_DEPLOYMENT_TARGET = "8.0"; 474 | LD_RUNPATH_SEARCH_PATHS = ( 475 | "$(inherited)", 476 | "@loader_path/../Frameworks", 477 | "@loader_path/Frameworks" 478 | ); 479 | MACOSX_DEPLOYMENT_TARGET = "10.10"; 480 | OTHER_CFLAGS = ( 481 | "$(inherited)" 482 | ); 483 | OTHER_LDFLAGS = ( 484 | "$(inherited)" 485 | ); 486 | OTHER_SWIFT_FLAGS = ( 487 | "$(inherited)" 488 | ); 489 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = ( 490 | "$(inherited)" 491 | ); 492 | SWIFT_VERSION = "5.0"; 493 | TARGET_NAME = "CSwiftVTests"; 494 | TVOS_DEPLOYMENT_TARGET = "9.0"; 495 | WATCHOS_DEPLOYMENT_TARGET = "2.0"; 496 | }; 497 | name = "Release"; 498 | }; 499 | "OBJ_41" = { 500 | isa = "PBXSourcesBuildPhase"; 501 | files = ( 502 | "OBJ_42" 503 | ); 504 | }; 505 | "OBJ_42" = { 506 | isa = "PBXBuildFile"; 507 | fileRef = "OBJ_12"; 508 | }; 509 | "OBJ_43" = { 510 | isa = "PBXFrameworksBuildPhase"; 511 | files = ( 512 | "OBJ_44" 513 | ); 514 | }; 515 | "OBJ_44" = { 516 | isa = "PBXBuildFile"; 517 | fileRef = "CSwiftV::CSwiftV::Product"; 518 | }; 519 | "OBJ_45" = { 520 | isa = "PBXTargetDependency"; 521 | target = "CSwiftV::CSwiftV"; 522 | }; 523 | "OBJ_5" = { 524 | isa = "PBXGroup"; 525 | children = ( 526 | "OBJ_6", 527 | "OBJ_7", 528 | "OBJ_10", 529 | "OBJ_13", 530 | "OBJ_16", 531 | "OBJ_17", 532 | "OBJ_18" 533 | ); 534 | path = ""; 535 | sourceTree = ""; 536 | }; 537 | "OBJ_6" = { 538 | isa = "PBXFileReference"; 539 | explicitFileType = "sourcecode.swift"; 540 | path = "Package.swift"; 541 | sourceTree = ""; 542 | }; 543 | "OBJ_7" = { 544 | isa = "PBXGroup"; 545 | children = ( 546 | "OBJ_8" 547 | ); 548 | name = "Sources"; 549 | path = ""; 550 | sourceTree = "SOURCE_ROOT"; 551 | }; 552 | "OBJ_8" = { 553 | isa = "PBXGroup"; 554 | children = ( 555 | "OBJ_9" 556 | ); 557 | name = "CSwiftV"; 558 | path = "Sources/CSwiftV"; 559 | sourceTree = "SOURCE_ROOT"; 560 | }; 561 | "OBJ_9" = { 562 | isa = "PBXFileReference"; 563 | path = "CSwiftV.swift"; 564 | sourceTree = ""; 565 | }; 566 | }; 567 | rootObject = "OBJ_1"; 568 | } 569 | -------------------------------------------------------------------------------- /CSwiftV.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | -------------------------------------------------------------------------------- /CSwiftV.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /CSwiftV.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded 6 | 7 | 8 | -------------------------------------------------------------------------------- /CSwiftV.xcodeproj/xcshareddata/xcschemes/CSwiftV-Package.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 55 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 74 | 76 | 77 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, Daniel Haight 2 | 3 | 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without modification, 7 | are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, 10 | this list of conditions and the following disclaimer. 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | * Neither the name of CSwiftV nor the names of its contributors 15 | may be used to endorse or promote products derived from this software 16 | without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 22 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 23 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 25 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.0 2 | import PackageDescription 3 | 4 | let package = Package( 5 | name: "CSwiftV", 6 | products: [ 7 | .library( 8 | name: "CSwiftV", 9 | targets: ["CSwiftV"]), 10 | ], 11 | targets: [ 12 | .target( 13 | name: "CSwiftV", 14 | dependencies: []), 15 | .testTarget( 16 | name: "CSwiftVTests", 17 | dependencies: ["CSwiftV"]), 18 | ] 19 | ) 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CSwiftV 2 | 3 | A csv parser conforming (and tested as much) to [rfc4180](http://tools.ietf.org/html/rfc4180#section-2) i.e the closest thing to a csv spec. 4 | 5 | It is currently all in memory so not suitable for very large files. 6 | 7 | ### TL;DR 8 | 9 | ```swift 10 | let inputString = "Year,Make,Model,Description,Price\r\n1997,Ford,E350,descrition,3000.00\r\n1999,Chevy,Venture,another description,4900.00\r\n" 11 | 12 | let csv = CSwiftV(with: inputString) 13 | 14 | let rows = csv.rows // [ 15 | // ["1997","Ford","E350","descrition","3000.00"], 16 | // ["1999","Chevy","Venture","another description","4900.00"] 17 | // ] 18 | 19 | let headers = csv.headers // ["Year","Make","Model","Description","Price"] 20 | 21 | let keyedRows = csv.keyedRows // [ 22 | // ["Year":"1997","Make":"Ford","Model":"E350","Description":"descrition","Price":"3000.00"], 23 | // ["Year":"1999","Make":"Chevy","Model":"Venture","Description":"another, description","Price":"4900.00"] 24 | // ] 25 | 26 | ``` 27 | -------------------------------------------------------------------------------- /Sources/CSwiftV/CSwiftV.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CSwiftV.swift 3 | // CSwiftV 4 | // 5 | // Created by Daniel Haight on 30/08/2014. 6 | // Copyright (c) 2014 ManyThings. All rights reserved. 7 | // 8 | 9 | import class Foundation.NSCharacterSet 10 | 11 | extension String { 12 | 13 | var isEmptyOrWhitespace: Bool { 14 | return isEmpty || trimmingCharacters(in: .whitespaces) == "" 15 | } 16 | 17 | var isNotEmptyOrWhitespace: Bool { 18 | return !isEmptyOrWhitespace 19 | } 20 | 21 | } 22 | 23 | // MARK: Parser 24 | public class CSwiftV { 25 | 26 | /// The number of columns in the data 27 | private let columnCount: Int 28 | /// The headers from the data, an Array of String 29 | public let headers: [String] 30 | /// An array of Dictionaries with the values of each row keyed to the header 31 | public let keyedRows: [[String: String]]? 32 | /// An Array of the rows in an Array of String form, equivalent to keyedRows, but without the keys 33 | public let rows: [[String]] 34 | 35 | /// Creates an instance containing the data extracted from the `with` String 36 | /// - Parameter with: The String obtained from reading the csv file. 37 | /// - Parameter separator: The separator used in the csv file, defaults to "," 38 | /// - Parameter headers: The array of headers from the file. If not included, it will be populated with the ones from the first line 39 | public init(with string: String, separator: String = ",", headers: [String]? = nil) { 40 | var parsedLines = CSwiftV.records(from: string.replacingOccurrences(of: "\r\n", with: "\n")).map { CSwiftV.cells(forRow: $0, separator: separator) } 41 | self.headers = headers ?? parsedLines.removeFirst() 42 | rows = parsedLines 43 | columnCount = self.headers.count 44 | 45 | let tempHeaders = self.headers 46 | keyedRows = rows.map { field -> [String: String] in 47 | var row = [String: String]() 48 | // Only store value which are not empty 49 | for (index, value) in field.enumerated() where value.isNotEmptyOrWhitespace { 50 | if index < tempHeaders.count { 51 | row[tempHeaders[index]] = value 52 | } 53 | } 54 | return row 55 | } 56 | } 57 | 58 | /// Creates an instance containing the data extracted from the `with` String 59 | /// - Parameter with: The string obtained from reading the csv file. 60 | /// - Parameter headers: The array of headers from the file. I f not included, it will be populated with the ones from the first line 61 | /// - Attention: In this conveniennce initializer, we assume that the separator between fields is "," 62 | public convenience init(with string: String, headers: [String]?) { 63 | self.init(with: string, separator:",", headers:headers) 64 | } 65 | 66 | /// Analizes a row and tries to obtain the different cells contained as an Array of String 67 | /// - Parameter forRow: The string corresponding to a row of the data matrix 68 | /// - Parameter separator: The string that delimites the cells or fields inside the row. Defaults to "," 69 | internal static func cells(forRow string: String, separator: String = ",") -> [String] { 70 | return CSwiftV.split(separator, string: string) 71 | } 72 | 73 | /// Analizes the CSV data as an String, and separates the different rows as an individual String each. 74 | /// - Parameter forRow: The string corresponding the whole data 75 | /// - Attention: Assumes "\n" as row delimiter, needs to filter string for "\r\n" first 76 | internal static func records(from string: String) -> [String] { 77 | return CSwiftV.split("\n", string: string).filter { $0.isNotEmptyOrWhitespace } 78 | } 79 | 80 | /// Tries to preserve the parity between open and close characters for different formats. Analizes the escape character count to do so 81 | private static func split(_ separator: String, string: String) -> [String] { 82 | func oddNumberOfQuotes(_ string: String) -> Bool { 83 | return string.components(separatedBy: "\"").count % 2 == 0 84 | } 85 | 86 | let initial = string.components(separatedBy: separator) 87 | var merged = [String]() 88 | for newString in initial { 89 | guard let record = merged.last , oddNumberOfQuotes(record) == true else { 90 | merged.append(newString) 91 | continue 92 | } 93 | merged.removeLast() 94 | let lastElem = record + separator + newString 95 | merged.append(lastElem) 96 | } 97 | return merged 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /Tests/CSwiftVTests/CSwiftVTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CSwiftVTests.swift 3 | // CSwiftVTests 4 | // 5 | // Created by Daniel Haight on 30/08/2014. 6 | // Copyright (c) 2014 ManyThings. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import XCTest 11 | 12 | @testable import CSwiftV 13 | 14 | public let emptyColumns = "Year,Make,Model,Description,Price\r\n1997,Ford,,descrition,3000.00\r\n1999,Chevy,Venture,another description,\r\n" 15 | 16 | public let newLineSeparation = "Year,Make,Model,Description,Price\r\n1997,Ford,E350,descrition,3000.00\r\n1999,Chevy,Venture,another description,4900.00\r\n" 17 | 18 | public let newLineSeparationNoCR = "Year,Make,Model,Description,Price\n1997,Ford,E350,descrition,3000.00\n1999,Chevy,Venture,another description,4900.00\n" 19 | 20 | public let newLineSeparationNoEnd = "Year,Make,Model,Description,Price\r\n1997,Ford,E350,descrition,3000.00\r\n1999,Chevy,Venture,another description,4900.00" 21 | 22 | public let withoutHeader = "1997,Ford,E350,descrition,3000.00\r\n1999,Chevy,Venture,another description,4900.00" 23 | 24 | public let longerColumns = "Year,Make,Model,Description,Price\r\n1997,Ford,E350,descrition,3000.00\r\n1999,Chevy,Venture,another description,4900.00,extra column\r\n" 25 | 26 | public let withRandomQuotes = "Year,Make,Model,Description,Price\r\n1997,Ford,\"E350\",descrition,3000.00\r\n1999,Chevy,Venture,\"another description\",4900.00" 27 | 28 | public let withCommasInQuotes = "Year,Make,Model,Description,Price\r\n1997,Ford,\"E350\",descrition,3000.00\r\n1999,Chevy,Venture,\"another, amazing, description\",4900.00" 29 | 30 | public let withQuotesInQuotes = "Year,Make,Model,Description,Price\r\n1997,Ford,\"E350\",descrition,3000.00\r\n1999,Chevy,Venture,\"another, \"\"amazing\"\", description\",4900.00" 31 | 32 | public let withNewLinesInQuotes = "Year,Make,Model,Description,Price\n1997,Ford,\"E350\",descrition,3000.00\n1999,Chevy,Venture,\"another, \"\"amazing\"\",\n\ndescription\n\",4900.00\n" 33 | 34 | public let withTabSeparator = "Year\tMake\tModel\tDescription\tPrice\r\n1997\tFord\t\"E350\"\tdescrition\t3000.00\r\n1999\tChevy\tVenture\t\"another\t \"\"amazing\"\"\t description\"\t4900.00\r\n" 35 | 36 | public let singleString = "1999,Chevy,Venture,\"another, \"\"amazing\"\",\n\ndescription\n\",4900.00" 37 | 38 | class CSwiftVTests: XCTestCase { 39 | 40 | lazy var nativeSwiftStringCSV: String = { 41 | var string = "Timestamp,Number1,Number2" 42 | for _ in 1...10_000 { 43 | string += ("20150101000100,100,0\n") 44 | } 45 | return string 46 | }() 47 | 48 | var testString: String! 49 | 50 | // modelling from http://tools.ietf.org/html/rfc4180#section-2 51 | 52 | //1. Each record is located on a separate line, delimited by a line 53 | //break (CRLF). For example: 54 | 55 | //aaa,bbb,ccc CRLF 56 | //zzz,yyy,xxx CRLF 57 | func testThatItParsesLinesSeperatedByNewLines() { 58 | testString = newLineSeparation 59 | 60 | let arrayUnderTest = CSwiftV(with: testString).rows 61 | 62 | let expectedArray = [ 63 | ["1997","Ford","E350","descrition","3000.00"], 64 | ["1999","Chevy","Venture","another description","4900.00"] 65 | ] 66 | 67 | XCTAssertEqual(arrayUnderTest[0], expectedArray[0]) 68 | XCTAssertEqual(arrayUnderTest[1], expectedArray[1]) 69 | } 70 | 71 | func testThatItParsesLinesSeperatedByNewLinesNoCR() { 72 | testString = newLineSeparationNoCR 73 | 74 | let arrayUnderTest = CSwiftV(with: testString).rows 75 | 76 | let expectedArray = [ 77 | ["1997","Ford","E350","descrition","3000.00"], 78 | ["1999","Chevy","Venture","another description","4900.00"] 79 | ] 80 | 81 | XCTAssertEqual(arrayUnderTest[0], expectedArray[0]) 82 | XCTAssertEqual(arrayUnderTest[1], expectedArray[1]) 83 | } 84 | 85 | //2. The last record in the file may or may not have an ending line 86 | //break. For example: 87 | 88 | //aaa,bbb,ccc CRLF 89 | //zzz,yyy,xxx 90 | 91 | func testThatItParsesLinesSeperatedByNewLinesWithoutNewLineAtEnd() { 92 | 93 | testString = newLineSeparationNoEnd 94 | 95 | let arrayUnderTest = CSwiftV(with: testString).rows 96 | 97 | let expectedArray = [ 98 | ["1997","Ford","E350","descrition","3000.00"], 99 | ["1999","Chevy","Venture","another description","4900.00"] 100 | ] 101 | 102 | XCTAssertEqual(arrayUnderTest[0], expectedArray[0]) 103 | XCTAssertEqual(arrayUnderTest[1], expectedArray[1]) 104 | } 105 | 106 | //3. There maybe an optional header line appearing as the first line 107 | //of the file with the same format as normal record lines. This 108 | //header will contain names corresponding to the fields in the file 109 | //and should contain the same number of fields as the records in 110 | //the rest of the file (the presence or absence of the header line 111 | //should be indicated via the optional "header" parameter of this 112 | //MIME type). For example: 113 | 114 | //field_name,field_name,field_name CRLF 115 | //aaa,bbb,ccc CRLF 116 | //zzz,yyy,xxx CRLF 117 | func testThatItParsesHeadersCorrectly() { 118 | 119 | testString = newLineSeparationNoEnd 120 | 121 | let arrayUnderTest : [String] = CSwiftV(with: testString).headers 122 | 123 | let expectedArray = ["Year","Make","Model","Description","Price"] 124 | 125 | XCTAssertEqual(arrayUnderTest, expectedArray) 126 | 127 | } 128 | 129 | // still 3. in RFC. This is the first decision we make in 130 | // api design with regards to headers. Currently if nothing 131 | // is passed in to the `headers` parameter (as is the case) 132 | // with the convenience initialiser. We assume that the csv 133 | // contains headers. If the headers are passed in, then we 134 | // assume that the csv file does not contain them and expect 135 | // it to be parsed accordingly. 136 | func testThatItParsesRowsWithoutHeaders() { 137 | 138 | testString = withoutHeader 139 | 140 | let arrayUnderTest = CSwiftV(with: testString, separator:",", headers:["Year","Make","Model","Description","Price"]).rows 141 | 142 | //XCTAssertNil(arrayUnderTest) 143 | 144 | let expectedArray = [ 145 | ["1997","Ford","E350","descrition","3000.00"], 146 | ["1999","Chevy","Venture","another description","4900.00"] 147 | ] 148 | 149 | XCTAssertEqual(arrayUnderTest[0], expectedArray[0]) 150 | XCTAssertEqual(arrayUnderTest[1], expectedArray[1]) 151 | } 152 | 153 | // Covers the case where a row is longer than the header row. 154 | func testThatItParsesRowsLongerThanHeaders() { 155 | 156 | testString = longerColumns 157 | let csv = CSwiftV(with: testString) 158 | 159 | let expectedArray = [ 160 | ["1997","Ford","E350","descrition","3000.00"], 161 | ["1999","Chevy","Venture","another description","4900.00","extra column"] 162 | ] 163 | 164 | XCTAssertEqual(csv.rows[0], expectedArray[0]) 165 | XCTAssertEqual(csv.rows[1], expectedArray[1]) 166 | 167 | let expectedKeyedRows = [ 168 | ["Year":"1997", "Make": "Ford", "Model": "E350", "Description": "descrition", "Price":"3000.00"], 169 | ["Year":"1999", "Make": "Chevy", "Model": "Venture", "Description":"another description", "Price":"4900.00"] 170 | ] 171 | 172 | XCTAssertEqual(csv.keyedRows![0], expectedKeyedRows[0]) 173 | XCTAssertEqual(csv.keyedRows![1], expectedKeyedRows[1]) 174 | } 175 | 176 | 177 | // 4. Within the header and each record, there may be one or more 178 | // fields, separated by commas. Each line should contain the same 179 | // number of fields throughout the file. Spaces are considered part 180 | // of a field and should not be ignored. The last field in the 181 | // record must not be followed by a comma. For example: 182 | // 183 | // aaa,bbb,ccc 184 | // 185 | // This is covered by previous test cases since there are spaces in 186 | // fields and no commas at the end of the lines 187 | // 188 | // 5. Each field may or may not be enclosed in double quotes (however 189 | // some programs, such as Microsoft Excel, do not use double quotes 190 | // at all). If fields are not enclosed with double quotes, then 191 | // double quotes may not appear inside the fields. For example: 192 | // 193 | // "aaa","bbb","ccc" CRLF 194 | // zzz,yyy,xxx 195 | func testThatItParsesFieldswithQuotes() { 196 | 197 | testString = withRandomQuotes 198 | 199 | let arrayUnderTest = CSwiftV(with: testString).rows 200 | 201 | let expectedArray = [ 202 | ["1997","Ford","\"E350\"","descrition","3000.00"], 203 | ["1999","Chevy","Venture","\"another description\"","4900.00"] 204 | ] 205 | 206 | XCTAssertEqual(arrayUnderTest[0], expectedArray[0]) 207 | XCTAssertEqual(arrayUnderTest[1], expectedArray[1]) 208 | } 209 | 210 | // 6. Fields containing line breaks (CRLF), double quotes, and commas 211 | // should be enclosed in double-quotes. For example: 212 | // 213 | // "aaa","b CRLF 214 | // bb","ccc" CRLF 215 | // zzz,yyy,xxx 216 | 217 | func testThatItParsesFieldswithCommasInQuotes() { 218 | 219 | testString = withCommasInQuotes 220 | 221 | let arrayUnderTest = CSwiftV(with: testString).rows 222 | 223 | let expectedArray = [ 224 | ["1997","Ford","\"E350\"","descrition","3000.00"], 225 | ["1999","Chevy","Venture","\"another, amazing, description\"","4900.00"] 226 | ] 227 | 228 | XCTAssertEqual(arrayUnderTest[0], expectedArray[0]) 229 | XCTAssertEqual(arrayUnderTest[1], expectedArray[1]) 230 | } 231 | 232 | func testThatItParsesFieldswithNewLinesInQuotes() { 233 | 234 | testString = withNewLinesInQuotes 235 | 236 | let arrayUnderTest = CSwiftV(with: testString).rows 237 | 238 | let expectedArray = [ 239 | ["1997","Ford","\"E350\"","descrition","3000.00"], 240 | ["1999","Chevy","Venture","\"another, \"\"amazing\"\",\n\ndescription\n\"","4900.00"] 241 | ] 242 | 243 | XCTAssertEqual(arrayUnderTest[0], expectedArray[0]) 244 | XCTAssertEqual(arrayUnderTest[1], expectedArray[1]) 245 | } 246 | 247 | // 7. If double-quotes are used to enclose fields, then a double-quote 248 | // appearing inside a field must be escaped by preceding it with 249 | // another double quote. For example: 250 | // 251 | // "aaa","b""bb","ccc" 252 | 253 | func testThatItParsesFieldswithQuotesInQuotes() { 254 | 255 | testString = withQuotesInQuotes 256 | 257 | let arrayUnderTest = CSwiftV(with: testString).rows 258 | 259 | let expectedArray = [ 260 | ["1997","Ford","\"E350\"","descrition","3000.00"], 261 | ["1999","Chevy","Venture","\"another, \"\"amazing\"\", description\"","4900.00"] 262 | ] 263 | 264 | XCTAssertEqual(arrayUnderTest[0], expectedArray[0]) 265 | XCTAssertEqual(arrayUnderTest[1], expectedArray[1]) 266 | } 267 | 268 | func testThatCanReturnKeyedRows() { 269 | 270 | testString = withQuotesInQuotes 271 | 272 | let arrayUnderTest = CSwiftV(with: testString).keyedRows! 273 | 274 | let expectedArray = [ 275 | ["Year":"1997","Make":"Ford","Model":"\"E350\"","Description":"descrition","Price":"3000.00"], 276 | ["Year":"1999","Make":"Chevy","Model":"Venture","Description":"\"another, \"\"amazing\"\", description\"","Price":"4900.00"] 277 | ] 278 | 279 | XCTAssertEqual(arrayUnderTest[0], expectedArray[0]) 280 | XCTAssertEqual(arrayUnderTest[1], expectedArray[1]) 281 | } 282 | 283 | func testThatItCanParseArbitrarySeparators() { 284 | 285 | testString = withTabSeparator 286 | 287 | let arrayUnderTest = CSwiftV(with: testString, separator:"\t").keyedRows! 288 | 289 | let expectedArray = [ 290 | ["Year":"1997","Make":"Ford","Model":"\"E350\"","Description":"descrition","Price":"3000.00"], 291 | ["Year":"1999","Make":"Chevy","Model":"Venture","Description":"\"another\t \"\"amazing\"\"\t description\"","Price":"4900.00"] 292 | ] 293 | 294 | XCTAssertEqual(arrayUnderTest[0], expectedArray[0]) 295 | XCTAssertEqual(arrayUnderTest[1], expectedArray[1]) 296 | } 297 | 298 | func testThatItCanGetCellsFromAstring() { 299 | testString = withNewLinesInQuotes 300 | 301 | let arrayUnderTest = CSwiftV.records(from: testString) 302 | 303 | let expectedArray = [ 304 | "Year,Make,Model,Description,Price", 305 | "1997,Ford,\"E350\",descrition,3000.00", 306 | "1999,Chevy,Venture,\"another, \"\"amazing\"\",\n\ndescription\n\",4900.00" 307 | ] 308 | 309 | XCTAssertEqual(arrayUnderTest, expectedArray) 310 | } 311 | 312 | 313 | func testThatItCanGetCells() { 314 | testString = singleString 315 | 316 | let arrayUnderTest = CSwiftV.cells(forRow: testString) 317 | 318 | let expectedArray = [ 319 | "1999", 320 | "Chevy", 321 | "Venture", 322 | "\"another, \"\"amazing\"\",\n\ndescription\n\"", 323 | "4900.00" 324 | ] 325 | 326 | XCTAssertEqual(arrayUnderTest, expectedArray) 327 | } 328 | 329 | func testWhenCellsAreEmpty() { 330 | 331 | testString = emptyColumns 332 | let csv = CSwiftV(with: testString) 333 | 334 | let expectedArray = [ 335 | ["1997","Ford","","descrition","3000.00"], 336 | ["1999","Chevy","Venture","another description",""] 337 | ] 338 | 339 | XCTAssertEqual(csv.rows[0], expectedArray[0]) 340 | XCTAssertEqual(csv.rows[1], expectedArray[1]) 341 | 342 | let expectedKeyedRows = [ 343 | ["Year":"1997", "Make": "Ford", "Description":"descrition", "Price":"3000.00"], 344 | ["Year":"1999", "Make": "Chevy", "Model":"Venture", "Description":"another description"] 345 | ] 346 | 347 | XCTAssertEqual(csv.keyedRows![0], expectedKeyedRows[0]) 348 | XCTAssertEqual(csv.keyedRows![1], expectedKeyedRows[1]) 349 | } 350 | 351 | func testPerformance() { 352 | let testString = nativeSwiftStringCSV 353 | measure { 354 | let _ = CSwiftV(with: testString) 355 | } 356 | } 357 | 358 | } 359 | -------------------------------------------------------------------------------- /Tests/CSwiftVTests/XCTestManifests.swift: -------------------------------------------------------------------------------- 1 | #if !canImport(ObjectiveC) 2 | import XCTest 3 | 4 | extension CSwiftVTests { 5 | // DO NOT MODIFY: This is autogenerated, use: 6 | // `swift test --generate-linuxmain` 7 | // to regenerate. 8 | static let __allTests__CSwiftVTests = [ 9 | ("testPerformance", testPerformance), 10 | ("testThatCanReturnKeyedRows", testThatCanReturnKeyedRows), 11 | ("testThatItCanGetCells", testThatItCanGetCells), 12 | ("testThatItCanGetCellsFromAstring", testThatItCanGetCellsFromAstring), 13 | ("testThatItCanParseArbitrarySeparators", testThatItCanParseArbitrarySeparators), 14 | ("testThatItParsesFieldswithCommasInQuotes", testThatItParsesFieldswithCommasInQuotes), 15 | ("testThatItParsesFieldswithNewLinesInQuotes", testThatItParsesFieldswithNewLinesInQuotes), 16 | ("testThatItParsesFieldswithQuotes", testThatItParsesFieldswithQuotes), 17 | ("testThatItParsesFieldswithQuotesInQuotes", testThatItParsesFieldswithQuotesInQuotes), 18 | ("testThatItParsesHeadersCorrectly", testThatItParsesHeadersCorrectly), 19 | ("testThatItParsesLinesSeperatedByNewLines", testThatItParsesLinesSeperatedByNewLines), 20 | ("testThatItParsesLinesSeperatedByNewLinesNoCR", testThatItParsesLinesSeperatedByNewLinesNoCR), 21 | ("testThatItParsesLinesSeperatedByNewLinesWithoutNewLineAtEnd", testThatItParsesLinesSeperatedByNewLinesWithoutNewLineAtEnd), 22 | ("testThatItParsesRowsLongerThanHeaders", testThatItParsesRowsLongerThanHeaders), 23 | ("testThatItParsesRowsWithoutHeaders", testThatItParsesRowsWithoutHeaders), 24 | ("testTheBadOne", testTheBadOne), 25 | ("testWhenCellsAreEmpty", testWhenCellsAreEmpty), 26 | ] 27 | } 28 | 29 | public func __allTests() -> [XCTestCaseEntry] { 30 | return [ 31 | testCase(CSwiftVTests.__allTests__CSwiftVTests), 32 | ] 33 | } 34 | #endif 35 | -------------------------------------------------------------------------------- /Tests/LinuxMain.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | 3 | import CSwiftVTests 4 | 5 | var tests = [XCTestCaseEntry]() 6 | tests += CSwiftVTests.__allTests() 7 | 8 | XCTMain(tests) 9 | --------------------------------------------------------------------------------