@_spi(Internal) import ConfigurationClient @_spi(Internal) import PandocClient import PlaybookClient import TestSupport import Testing @Suite("PandocClientTests") struct PandocClientTests: TestCase { static let outputDirectory = "/output" static let projectDirectory = "/project" static let defaultFileName = "Report" static let expectedIncludeInHeaders = [ "--include-in-header=/project/.build/head.tex", "--include-in-header=/project/.build/footer.tex", ] static let expectedFiles = [ "/project/.build/Report.md", "/project/.build/Definitions.md", ] static var sharedRunOptions: PandocClient.RunOptions { .init( buildDirectory: nil, files: nil, loggingOptions: loggingOptions, includeInHeader: nil, outputDirectory: outputDirectory, projectDirectory: projectDirectory, outputFileName: nil, quiet: false, shell: nil, shouldBuild: true ) } @Test func generateLatex() async throws { try await withCapturingCommandClient("generateLatex") { $0.configurationClient = .mock() $0.playbookClient.run.buildProject = { _ in } $0.pandocClient = .liveValue } run: { @Dependency(\.pandocClient) var pandocClient let output = try await pandocClient.run.generateLatex(Self.sharedRunOptions) #expect(output == "\(Self.outputDirectory)/\(Self.defaultFileName).tex") } assert: { output in let expected = ["pandoc"] + Self.expectedIncludeInHeaders + ["--output=\(Self.outputDirectory)/\(Self.defaultFileName).tex"] + Self.expectedFiles #expect(output.arguments == expected) } } @Test func generateHtml() async throws { try await withCapturingCommandClient("generateHtml") { $0.configurationClient = .mock() $0.playbookClient.run.buildProject = { _ in } $0.pandocClient = .liveValue } run: { @Dependency(\.pandocClient) var pandocClient let output = try await pandocClient.run.generateHtml(Self.sharedRunOptions) #expect(output == "\(Self.outputDirectory)/\(Self.defaultFileName).html") } assert: { output in let expected = [ "pandoc", "--output=\(Self.outputDirectory)/\(Self.defaultFileName).html", "\(Self.projectDirectory)/.build/Report.tex", ] #expect(output.arguments == expected) } } @Test( arguments: [ nil, "lualatex", ] ) func generatePdf(pdfEngine: String?) async throws { try await withCapturingCommandClient("generatePdf") { $0.configurationClient = .mock() $0.playbookClient.run.buildProject = { _ in } $0.pandocClient = .liveValue } run: { @Dependency(\.pandocClient) var pandocClient let output = try await pandocClient.run.generatePdf( Self.sharedRunOptions, pdfEngine: pdfEngine) #expect(output == "\(Self.outputDirectory)/\(Self.defaultFileName).pdf") } assert: { output in let expected = ["pandoc"] + Self.expectedIncludeInHeaders + ["--pdf-engine=\(pdfEngine ?? "xelatex")"] + ["--output=\(Self.outputDirectory)/\(Self.defaultFileName).pdf"] + Self.expectedFiles #expect(output.arguments == expected) } } @Test(arguments: TestPdfEngine.testCases) func parsePdfEngine(input: TestPdfEngine) { #expect(input.engine == input.expectedEngine) } @Test(arguments: TestParseFiles.testCases) func parseFiles(input: TestParseFiles) { #expect(input.parsedFiles == input.expectedFiles) } @Test(arguments: TestParseIncludeInHeaderFiles.testCases) func parseInclueInHeaderFiles(input: TestParseIncludeInHeaderFiles) { #expect(input.parsedFiles == input.expectedHeaderFiles) } @Test(arguments: TestParseOutputFileName.testCases) func parseOutputFileName(input: TestParseOutputFileName) { #expect(input.parsedFileName == input.expected) } @Test(arguments: TestParseBuildDirectory.testCases) func parseBuildDirectory(input: TestParseBuildDirectory) { #expect(input.parsedBuildDirectory == input.expected) } } struct TestPdfEngine: Sendable { let fileType: PandocClient.FileType let expectedEngine: String? let configuration: Configuration let defaults: Configuration.Generate var engine: String? { fileType.parsePdfEngine(configuration.generate, defaults) } static let testCases: [Self] = [ .init(fileType: .html, expectedEngine: nil, configuration: .init(), defaults: .default), .init(fileType: .latex, expectedEngine: nil, configuration: .init(), defaults: .default), .init( fileType: .pdf(engine: "lualatex"), expectedEngine: "lualatex", configuration: .init(), defaults: .default), .init( fileType: .pdf(engine: nil), expectedEngine: "xelatex", configuration: .init(), defaults: .default), .init( fileType: .pdf(engine: nil), expectedEngine: "xelatex", configuration: .init(), defaults: .init()), .init( fileType: .pdf(engine: nil), expectedEngine: "xelatex", configuration: .init(generate: .default), defaults: .init()), ] } struct TestParseFiles: Sendable { let expectedFiles: [String] let configuration: Configuration let defaults: Configuration.Generate let runOptions: PandocClient.RunOptions? init( expectedFiles: [String], configuration: Configuration = .init(), defaults: Configuration.Generate = .default, runOptions: PandocClient.RunOptions? = nil ) { self.expectedFiles = expectedFiles self.configuration = configuration self.defaults = defaults self.runOptions = runOptions } var parsedFiles: [String] { let runOptions = self.runOptions ?? PandocClient.RunOptions( loggingOptions: .init(commandName: "parseFiles", logLevel: .debug), projectDirectory: nil, quiet: true, shouldBuild: false ) return runOptions.parseFiles(configuration.generate, defaults) } static let testCases: [Self] = [ .init(expectedFiles: ["Report.md", "Definitions.md"]), .init( expectedFiles: ["Report.md", "Definitions.md"], configuration: .init(generate: .default), defaults: .init()), .init(expectedFiles: [], defaults: .init()), .init( expectedFiles: ["custom.md"], configuration: .init(), defaults: .init(), runOptions: .init( files: ["custom.md"], loggingOptions: .init(commandName: "parseFiles", logLevel: .debug), projectDirectory: nil, quiet: true, shouldBuild: false ) ), ] } struct TestParseIncludeInHeaderFiles: Sendable { let expectedHeaderFiles: [String] let configuration: Configuration let defaults: Configuration.Generate let runOptions: PandocClient.RunOptions? init( expectedHeaderFiles: [String], configuration: Configuration = .init(), defaults: Configuration.Generate = .default, runOptions: PandocClient.RunOptions? = nil ) { self.expectedHeaderFiles = expectedHeaderFiles self.configuration = configuration self.defaults = defaults self.runOptions = runOptions } var parsedFiles: [String] { let runOptions = self.runOptions ?? PandocClient.RunOptions( loggingOptions: .init(commandName: "parseFiles", logLevel: .debug) ) return runOptions.parseIncludeInHeader(configuration.generate, defaults) } static let testCases: [Self] = [ .init(expectedHeaderFiles: ["head.tex", "footer.tex"]), .init( expectedHeaderFiles: ["head.tex", "footer.tex"], configuration: .init(generate: .default), defaults: .init()), .init(expectedHeaderFiles: [], defaults: .init()), .init( expectedHeaderFiles: ["custom.tex"], configuration: .init(), defaults: .init(), runOptions: .init( loggingOptions: .init(commandName: "parseFiles", logLevel: .debug), includeInHeader: ["custom.tex"] ) ), ] } struct TestParseOutputFileName: Sendable { let expected: String let configuration: Configuration let defaults: Configuration.Generate let runOptions: PandocClient.RunOptions? init( expected: String, configuration: Configuration = .init(), defaults: Configuration.Generate = .default, runOptions: PandocClient.RunOptions? = nil ) { self.expected = expected self.configuration = configuration self.defaults = defaults self.runOptions = runOptions } var parsedFileName: String { let runOptions = self.runOptions ?? PandocClient.RunOptions( loggingOptions: .init(commandName: "parseFiles", logLevel: .debug) ) return runOptions.parseOutputFileName(configuration.generate, defaults) } static let testCases: [Self] = [ .init(expected: "Report"), .init(expected: "Report", configuration: .init(generate: .default), defaults: .init()), .init(expected: "Report", defaults: .init()), .init( expected: "custom", configuration: .init(), defaults: .init(), runOptions: .init( loggingOptions: .init(commandName: "parseFiles", logLevel: .debug), outputFileName: "custom" ) ), ] } struct TestParseBuildDirectory: Sendable { let expected: String let configuration: Configuration let defaults: Configuration.Generate let runOptions: PandocClient.RunOptions? init( expected: String = ".build", configuration: Configuration = .init(), defaults: Configuration.Generate = .default, runOptions: PandocClient.RunOptions? = nil ) { self.expected = expected self.configuration = configuration self.defaults = defaults self.runOptions = runOptions } var parsedBuildDirectory: String { let runOptions = self.runOptions ?? PandocClient.RunOptions( loggingOptions: .init(commandName: "parseFiles", logLevel: .debug) ) return runOptions.parseBuildDirectory(configuration.generate, defaults) } static let testCases: [Self] = [ .init(), .init(configuration: .init(generate: .default), defaults: .init()), .init(defaults: .init()), .init( expected: "custom", configuration: .init(), defaults: .init(), runOptions: .init( buildDirectory: "custom", loggingOptions: .init(commandName: "parseFiles", logLevel: .debug) ) ), ] }