Skip to content

Commit

Permalink
Added macOS compatibility to tests (#224)
Browse files Browse the repository at this point in the history
  • Loading branch information
Philip Niedertscheider authored Jul 19, 2020
1 parent b46be9e commit d0fc688
Show file tree
Hide file tree
Showing 66 changed files with 896 additions and 595 deletions.
21 changes: 20 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ stages:
jobs:
include:
- stage: Tests
name: "Unit Tests"
name: "iOS Unit Tests"
language: objective-c
env:
- TEST_FRAMEWORK_SCHEME="TPPDF-Package"
Expand All @@ -43,6 +43,25 @@ jobs:
after_success:
- bundle exec slather coverage -t --build-directory ${TRAVIS_BUILD_DIR}/derived_data
- bash <(curl -s https://codecov.io/bash) -f cobertura.xml -X coveragepy -X gco
- stage: Tests
name: "macOS Unit Tests"
language: objective-c
env:
- TEST_FRAMEWORK_SCHEME="TPPDF-Package"
- PROJECT="TPPDF.xcodeproj"
script:
- set -o pipefail
- swift package resolve
- set -o pipefail
- xcodebuild -project ${PROJECT}
-scheme ${TEST_FRAMEWORK_SCHEME}
-clonedSourcePackagesDirPath .
-derivedDataPath ${TRAVIS_BUILD_DIR}/derived_data
-sdk macosx
-destination "platform=macOS"
-configuration Debug
ONLY_ACTIVE_ARCH=YES
test | xcpretty

- stage: Examples
name: "Example iOS - Cocoapods"
Expand Down
4 changes: 3 additions & 1 deletion Example macOS/Example.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 1150;
LastUpgradeCheck = 1150;
LastUpgradeCheck = 1160;
ORGANIZATIONNAME = "techprimate GmbH & Co. KG";
TargetAttributes = {
D48C538424A269F400D7A3DD = {
Expand Down Expand Up @@ -478,6 +478,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ENTITLEMENTS = Example/Example.entitlements;
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Manual;
COMBINE_HIDPI_IMAGES = YES;
DEVELOPMENT_ASSET_PATHS = "\"Example/Preview Content\"";
Expand All @@ -502,6 +503,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ENTITLEMENTS = Example/Example.entitlements;
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Manual;
COMBINE_HIDPI_IMAGES = YES;
DEVELOPMENT_ASSET_PATHS = "\"Example/Preview Content\"";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1150"
LastUpgradeVersion = "1160"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
Expand Down
1 change: 1 addition & 0 deletions Example macOS/Example/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
window.setFrameAutosaveName("Main Window")
window.contentView = NSHostingView(rootView: contentView)
window.makeKeyAndOrderFront(nil)
window.setFrameAutosaveName("main")
}

func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
Expand Down
4 changes: 2 additions & 2 deletions Example macOS/Example/UI/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import TPPDF
class ContentViewModel: ObservableObject {

@Published var url: URL?
@State var selectedFactory = Examples.factories.first?.examples.first
@State var selectedFactory = Examples.defaultFactory

}

Expand All @@ -37,7 +37,7 @@ struct ContentView: View {
alignment: .topLeading)
.listStyle(SidebarListStyle())

DetailView(example: viewModel.selectedFactory!)
DetailView(example: viewModel.selectedFactory)
.frame(minWidth: 0, maxWidth: .infinity,
minHeight: 0, maxHeight: .infinity,
alignment: .topLeading)
Expand Down
4 changes: 4 additions & 0 deletions Shared/Examples/Examples.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,5 +48,9 @@ enum Examples {
])
]
}

static var defaultFactory: Example {
return factories[1].examples[0]
}
}

36 changes: 35 additions & 1 deletion Shared/Examples/TableExampleFactory.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class TableExampleFactory: ExampleFactory {
let document = PDFDocument(format: .a4)

// Create a table
let table = PDFTable(rows: 10, columns: 4)
var table = PDFTable(rows: 10, columns: 4)

// Tables can contain Strings, Numbers, Images or nil, in case you need an empty cell.
// If you add a unknown content type, an assertion will be thrown and the rendering will stop.
Expand Down Expand Up @@ -85,6 +85,40 @@ class TableExampleFactory: ExampleFactory {

document.add(table: table)

// Another table:

table = PDFTable(rows: 50, columns: 4)
table.widths = [0.1, 0.3, 0.3, 0.3]
table.margin = 10
table.padding = 10
table.showHeadersOnEveryPage = false
table.style.columnHeaderCount = 3

for row in 0..<table.size.rows {
table[row, 0].content = "\(row)".asTableContent
for column in 1..<table.size.columns {
table[row, column].content = "\(row),\(column)".asTableContent
}
}

for i in stride(from: 3, to: 48, by: 3) {
table[rows: i...(i + 2), column: 1].merge(with: PDFTableCell(content: Array(repeating: "\(i),1", count: 3).joined(separator: "\n").asTableContent,
alignment: .center))
}
for i in stride(from: 4, to: 47, by: 3) {
table[rows: i...(i + 2), column: 2].merge(with: PDFTableCell(content: Array(repeating: "\(i),2", count: 3).joined(separator: "\n").asTableContent,
alignment: .center))
}
for i in stride(from: 5, to: 48, by: 3) {
table[rows: i...(i + 2), column: 3].merge(with: PDFTableCell(content: Array(repeating: "\(i),3", count: 3).joined(separator: "\n").asTableContent,
alignment: .center))
}

table[rows: 0..<2, column: 2].merge()
table[rows: 1..<3, column: 3].merge()

document.add(table: table)

return [document]
}
}
2 changes: 1 addition & 1 deletion Source/API/Groups/PDFGroup+Objects.swift
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ public extension PDFGroup {
- parameter container: Container whose text color will be reset, defaults to `PDFGroupContainer.left`
*/
func resetFont(_ container: PDFGroupContainer = PDFGroupContainer.left) {
objects += [(container, PDFFontObject(font: Font.systemFont(ofSize: Font.systemFontSize)))]
objects += [(container, PDFFontObject(font: Font.systemFont(ofSize: PDFConstants.defaultFontSize)))]
}

/**
Expand Down
2 changes: 1 addition & 1 deletion Source/API/PDFDocument.swift
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ public class PDFDocument: CustomStringConvertible {
- parameter container: Container whose text color will be reset, defaults to `PDFContainer.contentLeft`
*/
public func resetFont(_ container: PDFContainer = PDFContainer.contentLeft) {
objects += [(container, PDFFontObject(font: Font.systemFont(ofSize: Font.systemFontSize)))]
objects += [(container, PDFFontObject(font: Font.systemFont(ofSize: PDFConstants.defaultFontSize)))]
}

/**
Expand Down
4 changes: 2 additions & 2 deletions Source/API/PDFGenerator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ public class PDFGenerator: PDFGeneratorProtocol, CustomStringConvertible {
These values are used for simple text objects
*/
internal lazy var fonts: [PDFContainer: Font] = .init(uniqueKeysWithValues: PDFContainer.allCases.map({ container in
(container, Font.systemFont(ofSize: Font.systemFontSize))
(container, Font.systemFont(ofSize: PDFConstants.defaultFontSize))
}))

/**
Expand Down Expand Up @@ -107,7 +107,7 @@ public class PDFGenerator: PDFGeneratorProtocol, CustomStringConvertible {
columnState.reset()
currentPage = 1
fonts = fonts.mapValues { _ in
Font.systemFont(ofSize: Font.systemFontSize)
Font.systemFont(ofSize: PDFConstants.defaultFontSize)
}
textColor = textColor.mapValues { _ in
Color.black
Expand Down
2 changes: 1 addition & 1 deletion Source/API/Section/PDFSectionColumn.swift
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ public class PDFSectionColumn: PDFDocumentObject {
- parameter container: Container whose text color will be reset, defaults to `PDFSectionColumnContainer.left`
*/
public func resetFont(_ container: PDFSectionColumnContainer = PDFSectionColumnContainer.left) {
objects += [(container, PDFFontObject(font: Font.systemFont(ofSize: Font.systemFontSize)))]
objects += [(container, PDFFontObject(font: Font.systemFont(ofSize: PDFConstants.defaultFontSize)))]
}

/**
Expand Down
2 changes: 1 addition & 1 deletion Source/API/Table/Content/PDFTableContent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import AppKit
/**
TODO: Documentation
*/
public class PDFTableContent {
public class PDFTableContent: CustomStringConvertible {

/**
TODO: Documentation
Expand Down
5 changes: 5 additions & 0 deletions Source/API/Table/PDFTable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ public class PDFTable: PDFDocumentObject {
*/
public var showHeadersOnEveryPage: Bool = false

/**
Cells should split when overlapping page
*/
public var shouldSplitCellsOnPageBeak = false

/**
Count of rows and columns in this table
*/
Expand Down
4 changes: 2 additions & 2 deletions Source/API/Table/Style/PDFTableCellStyle.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public struct PDFTableCellStyle {
*/
public init(colors: (fill: Color, text: Color) = (Color.clear, Color.black),
borders: PDFTableCellBorders = PDFTableCellBorders(),
font: Font = Font.systemFont(ofSize: Font.systemFontSize)) {
font: Font = Font.systemFont(ofSize: PDFConstants.defaultFontSize)) {
self.colors = colors
self.borders = borders
self.font = font
Expand All @@ -47,5 +47,5 @@ extension PDFTableCellStyle {

public static let none = PDFTableCellStyle(colors: (fill: Color.clear, text: Color.black),
borders: .none,
font: Font.systemFont(ofSize: Font.systemFontSize))
font: Font.systemFont(ofSize: PDFConstants.defaultFontSize))
}
10 changes: 10 additions & 0 deletions Source/API/Utils/PDFConstants.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import CoreGraphics

/// Constants used throught the framework
public class PDFConstants {

/// Default font size for objects
///
/// In earlier versions the default `UIFont.systemFontSize` was used, but during implementation of macOS support, findings showed that it `NSFont.systemFontSize` differs. Therefore the new default fontSize is declared here
public static let defaultFontSize: CGFloat = 17
}
5 changes: 5 additions & 0 deletions Source/API/Utils/PDFError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ public enum PDFError: Error {
*/
case tableCellWeakReferenceBroken

/// Indicates that the cell is too big to be rendered onto a single page
case tableCellTooBig(cell: PDFTableCell)

/**
TODO: Documentation
*/
Expand Down Expand Up @@ -87,6 +90,8 @@ public enum PDFError: Error {
return "Table index out of bounds: <index: \(index), length: \(length)>"
case .tableCellWeakReferenceBroken:
return "Weak reference in table cell is broken"
case .tableCellTooBig(let cell):
return "Table cell is too big to be rendered: \(cell)"
case .textObjectIsNil:
return "No text object has been set"
case .textObjectNotCalculated:
Expand Down
26 changes: 26 additions & 0 deletions Source/Internal/Graphics/PDFContextGraphics.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,32 @@ import CoreGraphics

internal enum PDFContextGraphics {

internal static func createBitmapContext(size: CGSize) -> CGContext? {
let colorSpace = CGColorSpaceCreateDeviceRGB()
let bytesPerPixel = 4
let bytesPerRow = bytesPerPixel * Int(size.width)
let rawData = malloc(Int(size.height) * bytesPerRow)
let bitsPerComponent = 8
return CGContext(data: rawData,
width: Int(size.width),
height: Int(size.height),
bitsPerComponent: bitsPerComponent,
bytesPerRow: bytesPerRow,
space: colorSpace,
bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue)
}

internal static func getImage(from context: CGContext, size: CGSize) -> Image? {
guard let cgImage = context.makeImage() else {
return nil
}
#if os(macOS)
return Image(cgImage: cgImage, size: size)
#elseif os(iOS)
return Image(cgImage: cgImage)
#endif
}

internal static func createPDFContext(url: URL, bounds: CGRect, info: PDFInfo) -> CGContext {
var mediaBox = bounds
guard let context = CGContext(url as CFURL, mediaBox: &mediaBox, info.generate() as CFDictionary) else {
Expand Down
5 changes: 3 additions & 2 deletions Source/Internal/Graphics/PDFGraphics.swift
Original file line number Diff line number Diff line change
Expand Up @@ -178,8 +178,9 @@ internal enum PDFGraphics {
let factor: CGFloat = min(3 * quality, 1)
let resizeFactor = factor.isZero ? 0.2 : factor

let size = CGSize(width: frame.width * resizeFactor,
height: frame.height * resizeFactor)
// If there is a floating point error, e.g. 24.000000000000004, then UIKit will use the next higher integer value, but AppKit does not
let size = CGSize(width: floor(frame.width * resizeFactor),
height: floor(frame.height * resizeFactor))

#if os(iOS)
UIGraphicsBeginImageContext(size)
Expand Down
2 changes: 1 addition & 1 deletion Source/Internal/Table/PDFTableObject.swift
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,7 @@ internal class PDFTableObject: PDFRenderObject {
.reduce([], +)
.map(\.1)
cellElements += outline

let sliceObject = createSliceObject(frame: cellFrame,
elements: cellElements,
minOffset: minOffset,
Expand Down
Loading

0 comments on commit d0fc688

Please sign in to comment.