Skip to content

Commit cb0b458

Browse files
committed
Merge branch 'more-convention-tests' of https://github.com/aciidb0mb3r/swift-package-manager
2 parents 9bb96ee + 77ef84b commit cb0b458

File tree

3 files changed

+218
-13
lines changed

3 files changed

+218
-13
lines changed

Sources/PackageLoading/PackageBuilder.swift

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -275,13 +275,7 @@ public struct PackageBuilder {
275275
}
276276
} else {
277277
modules = try maybeModules.map { path in
278-
let name: String
279-
if path == srcroot {
280-
name = manifest.name
281-
} else {
282-
name = path.basename
283-
}
284-
return try modulify(path, name: name, isTest: false)
278+
try modulify(path, name: path.basename, isTest: false)
285279
}
286280
}
287281

Sources/PackageModel/Product.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,21 @@ extension Product: CustomStringConvertible {
7070
}
7171
}
7272
}
73+
74+
extension ProductType: Equatable {}
75+
public func ==(lhs: ProductType, rhs: ProductType) -> Bool {
76+
switch (lhs, rhs) {
77+
case (.Executable, .Executable):
78+
return true
79+
case (.Executable, _):
80+
return false
81+
case (.Test, .Test):
82+
return true
83+
case (.Test, _):
84+
return false
85+
case (.Library(let lhsType), .Library(let rhsType)):
86+
return lhsType == rhsType
87+
case (.Library(_), _):
88+
return false
89+
}
90+
}

Tests/PackageLoading/ConventionTests.swift

Lines changed: 199 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,138 @@ class ConventionTests: XCTestCase {
440440
}
441441
}
442442

443+
func testValidSources() throws {
444+
var fs = InMemoryFileSystem()
445+
try fs.createEmptyFiles("/main.swift",
446+
"/noExtension",
447+
"/Package.swift",
448+
"/.git/anchor",
449+
"/.xcodeproj/anchor",
450+
"/.playground/anchor",
451+
"/Package.swift",
452+
"/Packages/MyPackage/main.c")
453+
let name = "pkg"
454+
PackageBuilderTester(name, in: fs) { result in
455+
result.checkModule(name) { moduleResult in
456+
moduleResult.check(type: .executable, isTest: false)
457+
moduleResult.checkSources(root: "/", paths: "main.swift")
458+
}
459+
}
460+
}
461+
462+
func testCustomTargetDependencies() throws {
463+
var fs = InMemoryFileSystem()
464+
try fs.createEmptyFiles("/Sources/Foo/Foo.swift",
465+
"/Sources/Bar/Bar.swift",
466+
"/Sources/Baz/Baz.swift")
467+
468+
// Direct.
469+
var package = PackageDescription.Package(name: "pkg", targets: [Target(name: "Foo", dependencies: ["Bar"])])
470+
PackageBuilderTester(package, in: fs) { result in
471+
result.checkModule("Foo") { moduleResult in
472+
moduleResult.check(c99name: "Foo", type: .library, isTest: false)
473+
moduleResult.checkSources(root: "/Sources/Foo", paths: "Foo.swift")
474+
moduleResult.check(dependencies: ["Bar"])
475+
moduleResult.check(recursiveDependencies: ["Bar"])
476+
}
477+
478+
for module in ["Bar", "Baz"] {
479+
result.checkModule(module) { moduleResult in
480+
moduleResult.check(c99name: module, type: .library, isTest: false)
481+
moduleResult.checkSources(root: "/Sources/\(module)", paths: "\(module).swift")
482+
}
483+
}
484+
}
485+
486+
// Transitive.
487+
package = PackageDescription.Package(name: "pkg",
488+
targets: [Target(name: "Foo", dependencies: ["Bar"]),
489+
Target(name: "Bar", dependencies: ["Baz"])])
490+
PackageBuilderTester(package, in: fs) { result in
491+
result.checkModule("Foo") { moduleResult in
492+
moduleResult.check(c99name: "Foo", type: .library, isTest: false)
493+
moduleResult.checkSources(root: "/Sources/Foo", paths: "Foo.swift")
494+
moduleResult.check(dependencies: ["Bar"])
495+
moduleResult.check(recursiveDependencies: ["Baz", "Bar"])
496+
}
497+
498+
result.checkModule("Bar") { moduleResult in
499+
moduleResult.check(c99name: "Bar", type: .library, isTest: false)
500+
moduleResult.checkSources(root: "/Sources/Bar", paths: "Bar.swift")
501+
moduleResult.check(dependencies: ["Baz"])
502+
moduleResult.check(recursiveDependencies: ["Baz"])
503+
}
504+
505+
result.checkModule("Baz") { moduleResult in
506+
moduleResult.check(c99name: "Baz", type: .library, isTest: false)
507+
moduleResult.checkSources(root: "/Sources/Baz", paths: "Baz.swift")
508+
}
509+
}
510+
}
511+
512+
func testManifestTargetDeclErrors() throws {
513+
// Reference a target which doesn't exist.
514+
var fs = InMemoryFileSystem()
515+
try fs.createEmptyFiles("/Foo.swift")
516+
var package = PackageDescription.Package(name: "pkg", targets: [Target(name: "Random")])
517+
PackageBuilderTester(package, in: fs) { result in
518+
result.checkDiagnostic("these referenced modules could not be found: Random fix: reference only valid modules")
519+
}
520+
521+
// Reference an invalid dependency.
522+
package = PackageDescription.Package(name: "pkg", targets: [Target(name: "pkg", dependencies: ["Foo"])])
523+
PackageBuilderTester(package, in: fs) { result in
524+
result.checkDiagnostic("these referenced modules could not be found: Foo fix: reference only valid modules")
525+
}
526+
527+
// Executable as dependency.
528+
// FIXME: maybe should support this and condiser it as build order dependency.
529+
fs = InMemoryFileSystem()
530+
try fs.createEmptyFiles("/Sources/exec/main.swift",
531+
"/Sources/lib/lib.swift")
532+
package = PackageDescription.Package(name: "pkg", targets: [Target(name: "lib", dependencies: ["exec"])])
533+
PackageBuilderTester(package, in: fs) { result in
534+
result.checkDiagnostic("the target lib cannot have the executable exec as a dependency fix: move the shared logic inside a library, which can be referenced from both the target and the executable")
535+
}
536+
}
537+
538+
func testProducts() throws {
539+
var fs = InMemoryFileSystem()
540+
try fs.createEmptyFiles("/Sources/Foo/Foo.swift",
541+
"/Sources/Bar/Bar.swift")
542+
let products = [Product(name: "libpm", type: .Library(.Dynamic), modules: ["Foo", "Bar"])]
543+
544+
PackageBuilderTester("pkg", in: fs, products: products) { result in
545+
result.checkModule("Foo") { moduleResult in
546+
moduleResult.check(c99name: "Foo", type: .library, isTest: false)
547+
moduleResult.checkSources(root: "/Sources/Foo", paths: "Foo.swift")
548+
}
549+
550+
result.checkModule("Bar") { moduleResult in
551+
moduleResult.check(c99name: "Bar", type: .library, isTest: false)
552+
moduleResult.checkSources(root: "/Sources/Bar", paths: "Bar.swift")
553+
}
554+
555+
result.checkProduct("libpm") { productResult in
556+
productResult.check(type: .Library(.Dynamic), modules: ["Foo", "Bar"])
557+
}
558+
}
559+
}
560+
561+
func testBadProducts() throws {
562+
var fs = InMemoryFileSystem()
563+
try fs.createEmptyFiles("/Foo.swift")
564+
var products = [Product(name: "libpm", type: .Library(.Dynamic), modules: ["Foo", "Bar"])]
565+
PackageBuilderTester("Foo", in: fs, products: products) { result in
566+
result.checkDiagnostic("the product named libpm references a module that could not be found: Bar fix: reference only valid modules from the product")
567+
}
568+
569+
products = [Product(name: "libpm", type: .Library(.Dynamic), modules: [])]
570+
PackageBuilderTester("Foo", in: fs, products: products) { result in
571+
result.checkDiagnostic("the product named libpm doesn\'t reference any modules fix: reference one or more modules from the product")
572+
}
573+
}
574+
443575
// MARK:- Invalid Layouts Tests
444576

445577
func testMultipleRoots() throws {
@@ -552,6 +684,36 @@ class ConventionTests: XCTestCase {
552684
}
553685
}
554686

687+
func testNoSourcesInModule() throws {
688+
let fs = InMemoryFileSystem()
689+
try fs.createDirectory(AbsolutePath("/Sources/Module"), recursive: true)
690+
691+
PackageBuilderTester("MyPackage", in: fs) { result in
692+
result.checkDiagnostic("the module at /Sources/Module does not contain any source files fix: either remove the module folder, or add a source file to the module")
693+
}
694+
}
695+
696+
func testExcludes() throws {
697+
var fs = InMemoryFileSystem()
698+
try fs.createEmptyFiles("/Sources/A/main.swift",
699+
"/Sources/A/foo.swift", // File will be excluded.
700+
"/Sources/B/main.swift" // Dir will be excluded.
701+
)
702+
703+
// Excluding everything.
704+
var package = PackageDescription.Package(name: "pkg", exclude: ["."])
705+
PackageBuilderTester(package, in: fs) { _ in }
706+
707+
// Test excluding a file and a directory.
708+
package = PackageDescription.Package(name: "pkg", exclude: ["Sources/A/foo.swift", "Sources/B"])
709+
PackageBuilderTester(package, in: fs) { result in
710+
result.checkModule("A") { moduleResult in
711+
moduleResult.check(type: .executable, isTest: false)
712+
moduleResult.checkSources(root: "/Sources/A", paths: "main.swift")
713+
}
714+
}
715+
}
716+
555717
static var allTests = [
556718
("testCInTests", testCInTests),
557719
("testDotFilesAreIgnored", testDotFilesAreIgnored),
@@ -573,6 +735,13 @@ class ConventionTests: XCTestCase {
573735
("testInvalidLayout3", testInvalidLayout3),
574736
("testInvalidLayout4", testInvalidLayout4),
575737
("testInvalidLayout5", testInvalidLayout5),
738+
("testNoSourcesInModule", testNoSourcesInModule),
739+
("testValidSources", testValidSources),
740+
("testExcludes", testExcludes),
741+
("testCustomTargetDependencies", testCustomTargetDependencies),
742+
("testManifestTargetDeclErrors", testManifestTargetDeclErrors),
743+
("testProducts", testProducts),
744+
("testBadProducts", testBadProducts),
576745
]
577746
}
578747

@@ -613,11 +782,12 @@ private extension FileSystem {
613782
/// - package: PackageDescription instance to use for loading this package.
614783
/// - path: Directory where the package is located.
615784
/// - in: FileSystem in which the package should be loaded from.
785+
/// - products: List of products in the package.
616786
/// - warningStream: OutputByteStream to be passed to package builder.
617787
///
618788
/// - Throws: ModuleError, ProductError
619-
private func loadPackage(_ package: PackageDescription.Package, path: AbsolutePath, in fs: FileSystem, warningStream: OutputByteStream) throws -> PackageModel.Package {
620-
let manifest = Manifest(path: path.appending(component: Manifest.filename), url: "", package: package, products: [], version: nil)
789+
private func loadPackage(_ package: PackageDescription.Package, path: AbsolutePath, in fs: FileSystem, products: [PackageDescription.Product], warningStream: OutputByteStream) throws -> PackageModel.Package {
790+
let manifest = Manifest(path: path.appending(component: Manifest.filename), url: "", package: package, products: products, version: nil)
621791
let builder = PackageBuilder(manifest: manifest, path: path, fileSystem: fs, warningStream: warningStream)
622792
return try builder.construct(includingTestModules: true)
623793
}
@@ -650,16 +820,16 @@ final class PackageBuilderTester {
650820
var ignoreOtherModules: Bool = false
651821

652822
@discardableResult
653-
convenience init(_ name: String, path: AbsolutePath = .root, in fs: FileSystem, file: StaticString = #file, line: UInt = #line, _ body: @noescape (PackageBuilderTester) -> Void) {
823+
convenience init(_ name: String, path: AbsolutePath = .root, in fs: FileSystem, products: [PackageDescription.Product] = [], file: StaticString = #file, line: UInt = #line, _ body: @noescape (PackageBuilderTester) -> Void) {
654824
let package = Package(name: name)
655-
self.init(package, path: path, in: fs, file: file, line: line, body)
825+
self.init(package, path: path, in: fs, products: products, file: file, line: line, body)
656826
}
657827

658828
@discardableResult
659-
init(_ package: PackageDescription.Package, path: AbsolutePath = .root, in fs: FileSystem, file: StaticString = #file, line: UInt = #line, _ body: @noescape (PackageBuilderTester) -> Void) {
829+
init(_ package: PackageDescription.Package, path: AbsolutePath = .root, in fs: FileSystem, products: [PackageDescription.Product] = [], file: StaticString = #file, line: UInt = #line, _ body: @noescape (PackageBuilderTester) -> Void) {
660830
do {
661831
let warningStream = BufferedOutputByteStream()
662-
let loadedPackage = try loadPackage(package, path: path, in: fs, warningStream: warningStream)
832+
let loadedPackage = try loadPackage(package, path: path, in: fs, products: products, warningStream: warningStream)
663833
result = .package(loadedPackage)
664834
uncheckedModules = Set(loadedPackage.allModules)
665835
// FIXME: Find a better way. Maybe Package can keep array of warnings.
@@ -703,6 +873,29 @@ final class PackageBuilderTester {
703873
body?(ModuleResult(module))
704874
}
705875

876+
func checkProduct(_ name: String, file: StaticString = #file, line: UInt = #line, _ body: (@noescape (ProductResult) -> Void)? = nil) {
877+
guard case .package(let package) = result else {
878+
return XCTFail("Expected package did not load \(self)", file: file, line: line)
879+
}
880+
guard let product = package.products.first(where: {$0.name == name}) else {
881+
return XCTFail("Product: \(name) not found", file: file, line: line)
882+
}
883+
body?(ProductResult(product))
884+
}
885+
886+
final class ProductResult {
887+
private let product: PackageModel.Product
888+
889+
init(_ product: PackageModel.Product) {
890+
self.product = product
891+
}
892+
893+
func check(type: PackageDescription.ProductType, modules: [String], file: StaticString = #file, line: UInt = #line) {
894+
XCTAssertEqual(product.type, type, file: file, line: line)
895+
XCTAssertEqual(product.modules.map{$0.name}, modules, file: file, line: line)
896+
}
897+
}
898+
706899
final class ModuleResult {
707900
private let module: Module
708901

0 commit comments

Comments
 (0)