Search code examples
swiftswift-package-manager

getting file in path SPM swift


I have a package in SPM and I am dealing with file system. The problem I am facing now is my test case fails when I try getting the file like json file. here is my code and my test case.

Mt test

func testBundle() -> Bundle? {
        return Bundle(for: LandingPageSerializationTests.self)
    }
    
    func parseLandingPage(fromFile filename: String?) -> LandingPage? {
        let path = testBundle()?.path(forResource: filename, ofType: nil, inDirectory: kConfigFileFolder)
        XCTAssertNotNil(path)
        
        let data = NSData(contentsOfFile: path) as Data?
        XCTAssertNotNil(data)
        
        var asDict: [String: Any]? = nil
        do {
            if let data = data {
                asDict = try JSONSerialization.jsonObject(with: data, options: []) as? [String : Any]
            }
        } catch {
        }
        XCTAssertNotNil(asDict)
        
        return LandingPageSerialization.landingPage(fromJson: asDict)
    }

My Package.swift

let package = Package(
    name: "XXXX",
    platforms: [.iOS(.v11)],
    products: [
        // Products define the executables and libraries a package produces, and make them visible to other packages.
        .library(
            name: "XXXX",
            targets: ["XXXX"]),
    ],
    dependencies: [
        // Dependencies declare other packages that this package depends on.
    ],
    targets: [
        // Targets are the basic building blocks of a package. A target can define a module or a test suite.
        // Targets can depend on other targets in this package, and on products in packages this package depends on.
        .target(
            name: "XXXX",
            dependencies: [
            ],
            resources: [
                .process("Resources"),
            ]
        ),
        .testTarget(
            name: "XXXXTests",
            dependencies: ["XXXX"],
            resources: [
                .process("Resources"),
            ]
        ),

    ]
)

I do not know why I keep getting nil for the path despite specific name mentioned.


Solution

  • The line

    resources: [
        .process("Resources"),
    ]
    

    would be right if this was a file called Resources. If Resources is a folder, you want .copy, not .process.

    Also, I don't believe you can fetch a resource from the package's test target bundle in the way you're trying to do. You need to fetch it from the package's main target bundle, which you can do by saying Bundle.module.

    Here's a demo. This is the organization of my package:

    enter image description here

    This is my package declaration:

    let package = Package(
        name: "XXXXX",
        products: [
            .library(
                name: "XXXXX",
                targets: ["XXXXX"]),
        ],
        dependencies: [
        ],
        targets: [
            .target(
                name: "XXXXX",
                dependencies: [],
                resources: [.copy("Resources")]),
            .testTarget(
                name: "XXXXXTests",
                dependencies: ["XXXXX"]),
        ]
    )
    

    And this is a test method that works:

    func testExample() throws {
        let b = Bundle.module
        let url = b.url(forResource: "test", withExtension: "json", subdirectory: "Resources")
        let urlreal = try XCTUnwrap(url)
        let data = try Data(contentsOf: urlreal)
        let result = try JSONSerialization.jsonObject(with: data, options: [])
        let resultreal = try XCTUnwrap(result as? [String:Any]) // dictionary
        XCTAssertEqual(resultreal["name"] as? String ?? "", "Matt")
    }