From 69ba5a53bfc6e255bc49d1523c932992ee7b7cd8 Mon Sep 17 00:00:00 2001 From: Thibaut Schmitt Date: Tue, 6 Sep 2022 15:35:15 +0200 Subject: [PATCH] Add som units tests (split some code to made some part testable) --- Sources/ResgenSwift/Colors/Colors.swift | 13 - .../Generator/ColorExtensionGenerator.swift | 18 +- .../Colors/Parser/ColorFileParser.swift | 64 +-- .../Fonts/Generator/FontPlistGenerator.swift | 2 +- .../Generator/FontToolContentGenerator.swift | 22 +- .../Generator/ImageExtensionGenerator.swift | 70 ++-- Sources/ResgenSwift/Images/Images.swift | 10 +- .../Images/Parser/ImageFileParser.swift | 7 +- .../Generator/StringsFileGenerator.swift | 76 ++-- .../Strings/Generator/TagsGenerator.swift | 72 ++-- Sources/ToolCore/StringExtensions.swift | 1 + .../Colors/ColorExtensionGeneratorTests.swift | 85 ++++ .../Colors/ColorFileParserTests.swift | 98 +++++ .../Colors/ParsedColorTests.swift | 91 +++++ .../Extensions/StringExtensions.swift | 19 + .../Fonts/FontExtensionGeneratorTests.swift | 57 +++ .../Fonts/FontNameTests.swift | 83 ++++ .../Fonts/FontPlistGeneratorTests.swift | 35 ++ .../Images/ImageExtensionGeneratorTests.swift | 85 ++++ .../Images/ImageFileParserTests.swift | 50 +++ .../Images/ParsedImageTests.swift | 119 ++++++ Tests/ResgenSwiftTests/ResgenSwiftTests.swift | 2 + .../Strings/DefinitionTests.swift | 374 ++++++++++++++++++ .../Strings/SectionTests.swift | 104 +++++ .../Strings/StringsFileGeneratorTests.swift | 255 ++++++++++++ .../Strings/TagsGeneratorTests.swift | 82 ++++ 26 files changed, 1738 insertions(+), 156 deletions(-) create mode 100644 Tests/ResgenSwiftTests/Colors/ColorExtensionGeneratorTests.swift create mode 100644 Tests/ResgenSwiftTests/Colors/ColorFileParserTests.swift create mode 100644 Tests/ResgenSwiftTests/Colors/ParsedColorTests.swift create mode 100644 Tests/ResgenSwiftTests/Extensions/StringExtensions.swift create mode 100644 Tests/ResgenSwiftTests/Fonts/FontExtensionGeneratorTests.swift create mode 100644 Tests/ResgenSwiftTests/Fonts/FontNameTests.swift create mode 100644 Tests/ResgenSwiftTests/Fonts/FontPlistGeneratorTests.swift create mode 100644 Tests/ResgenSwiftTests/Images/ImageExtensionGeneratorTests.swift create mode 100644 Tests/ResgenSwiftTests/Images/ImageFileParserTests.swift create mode 100644 Tests/ResgenSwiftTests/Images/ParsedImageTests.swift create mode 100644 Tests/ResgenSwiftTests/Strings/DefinitionTests.swift create mode 100644 Tests/ResgenSwiftTests/Strings/SectionTests.swift create mode 100644 Tests/ResgenSwiftTests/Strings/StringsFileGeneratorTests.swift create mode 100644 Tests/ResgenSwiftTests/Strings/TagsGeneratorTests.swift diff --git a/Sources/ResgenSwift/Colors/Colors.swift b/Sources/ResgenSwift/Colors/Colors.swift index 1f161f2..b0cc2c8 100644 --- a/Sources/ResgenSwift/Colors/Colors.swift +++ b/Sources/ResgenSwift/Colors/Colors.swift @@ -108,16 +108,3 @@ struct Colors: ParsableCommand { } } } - -/* - Command samples: - - 1. UIColor extension without suffix - swift run -c release ColorToolCore -f ./SampleFiles/Colors/sampleColors1.txt --style all --xcassets-path "./SampleFiles/Colors/colors.xcassets" --extension-output-path "./SampleFiles/Colors/Generated/" --extension-name "UIColor" - - 2. UIColor extension with custom suffix - swift run -c release ColorToolCore -f ./SampleFiles/Colors/sampleColors1.txt --style all --xcassets-path "./SampleFiles/Colors/colors.xcassets" --extension-output-path "./SampleFiles/Colors/Generated/" --extension-name "UIColor" --extension-suffix "SampleApp" - - 3. Custom extension with only light theme colors (R2Color) - swift run -c release ColorToolCore -f ./SampleFiles/Colors/sampleColors1.txt --style light --xcassets-path "./SampleFiles/Colors/colors.xcassets" --extension-output-path "./SampleFiles/Colors/Generated/" --extension-name "R2Color" - */ diff --git a/Sources/ResgenSwift/Colors/Generator/ColorExtensionGenerator.swift b/Sources/ResgenSwift/Colors/Generator/ColorExtensionGenerator.swift index 4dd4642..6221896 100644 --- a/Sources/ResgenSwift/Colors/Generator/ColorExtensionGenerator.swift +++ b/Sources/ResgenSwift/Colors/Generator/ColorExtensionGenerator.swift @@ -15,12 +15,9 @@ struct ColorExtensionGenerator { static func writeExtensionFile(colors: [ParsedColor], staticVar: Bool, extensionName: String, extensionFilePath: String) { // Create extension content - let extensionContent = [ - Self.getHeader(extensionClassname: extensionName), - Self.getProperties(for: colors, withStaticVar: staticVar), - Self.getFooter() - ] - .joined(separator: "\n") + let extensionContent = Self.getExtensionContent(colors: colors, + staticVar: staticVar, + extensionName: extensionName) // Write content let extensionFilePathURL = URL(fileURLWithPath: extensionFilePath) @@ -33,6 +30,15 @@ struct ColorExtensionGenerator { } } + static func getExtensionContent(colors: [ParsedColor], staticVar: Bool, extensionName: String) -> String { + [ + Self.getHeader(extensionClassname: extensionName), + Self.getProperties(for: colors, withStaticVar: staticVar), + Self.getFooter() + ] + .joined(separator: "\n") + } + private static func getHeader(extensionClassname: String) -> String { """ // Generated by ResgenSwift.\(Colors.toolName) \(ResgenSwiftVersion) diff --git a/Sources/ResgenSwift/Colors/Parser/ColorFileParser.swift b/Sources/ResgenSwift/Colors/Parser/ColorFileParser.swift index 188fffb..70393fe 100644 --- a/Sources/ResgenSwift/Colors/Parser/ColorFileParser.swift +++ b/Sources/ResgenSwift/Colors/Parser/ColorFileParser.swift @@ -14,37 +14,43 @@ class ColorFileParser { let colorsByLines = inputFileContent.components(separatedBy: CharacterSet.newlines) // Iterate on each line of input file - return colorsByLines.enumerated().compactMap { lineNumber, colorLine in - // Required format: - // colorName="#RGB/#ARGB", colorName "#RGB/#ARGB", colorName "#RGB/#ARGB" "#RGB/#ARGB" - let colorLineCleanedUp = colorLine - .removeLeadingWhitespace() - .removeTrailingWhitespace() - .replacingOccurrences(of: "=", with: "") // Keep compat with current file format - - guard colorLineCleanedUp.hasPrefix("#") == false, colorLineCleanedUp.isEmpty == false else { - // debugPrint("[\(Colors.toolName)] ⚠️ BadFormat or empty line (line number: \(lineNumber + 1)). Skip this line") - return nil - } - - let colorContent = colorLineCleanedUp.split(separator: " ") - - guard colorContent.count >= 2 else { - let error = ColorsToolError.badFormat(colorLine) - print(error.localizedDescription) - Colors.exit(withError: error) - } - - switch colorStyle { - case .light: - return ParsedColor(name: String(colorContent[0]), light: String(colorContent[1]), dark: String(colorContent[1])) + return parseLines(lines: colorsByLines, colorStyle: colorStyle) + } + + static func parseLines(lines: [String], colorStyle: ColorStyle) -> [ParsedColor] { + lines + .enumerated() + .compactMap { lineNumber, colorLine in + // Required format: + // colorName = "#RGB/#ARGB", colorName "#RGB/#ARGB", colorName "#RGB/#ARGB" "#RGB/#ARGB" + let colorLineCleanedUp = colorLine + .removeLeadingWhitespace() + .removeTrailingWhitespace() + .replacingOccurrences(of: "=", with: "") // Keep compat with current file format - case .all: - if colorContent.count == 3 { - return ParsedColor(name: String(colorContent[0]), light: String(colorContent[1]), dark: String(colorContent[2])) + guard colorLineCleanedUp.hasPrefix("#") == false, colorLineCleanedUp.isEmpty == false else { + // debugPrint("[\(Colors.toolName)] ⚠️ BadFormat or empty line (line number: \(lineNumber + 1)). Skip this line") + return nil + } + + let colorContent = colorLineCleanedUp.split(separator: " ") + + guard colorContent.count >= 2 else { + let error = ColorsToolError.badFormat(colorLine) + print(error.localizedDescription) + Colors.exit(withError: error) + } + + switch colorStyle { + case .light: + return ParsedColor(name: String(colorContent[0]), light: String(colorContent[1]), dark: String(colorContent[1])) + + case .all: + if colorContent.count == 3 { + return ParsedColor(name: String(colorContent[0]), light: String(colorContent[1]), dark: String(colorContent[2])) + } + return ParsedColor(name: String(colorContent[0]), light: String(colorContent[1]), dark: String(colorContent[1])) } - return ParsedColor(name: String(colorContent[0]), light: String(colorContent[1]), dark: String(colorContent[1])) } - } } } diff --git a/Sources/ResgenSwift/Fonts/Generator/FontPlistGenerator.swift b/Sources/ResgenSwift/Fonts/Generator/FontPlistGenerator.swift index 00eca37..b02de76 100644 --- a/Sources/ResgenSwift/Fonts/Generator/FontPlistGenerator.swift +++ b/Sources/ResgenSwift/Fonts/Generator/FontPlistGenerator.swift @@ -15,7 +15,7 @@ class FontPlistGenerator { .forEach { plistData += "\t\t\($0)\n" } - plistData += "\t\n*/" + plistData += "\t" return plistData } diff --git a/Sources/ResgenSwift/Fonts/Generator/FontToolContentGenerator.swift b/Sources/ResgenSwift/Fonts/Generator/FontToolContentGenerator.swift index 7e8a472..992e55d 100644 --- a/Sources/ResgenSwift/Fonts/Generator/FontToolContentGenerator.swift +++ b/Sources/ResgenSwift/Fonts/Generator/FontToolContentGenerator.swift @@ -12,13 +12,9 @@ class FontExtensionGenerator { static func writeExtensionFile(fontsNames: [String], staticVar: Bool, extensionName: String, extensionFilePath: String) { // Create extension content - let extensionContent = [ - Self.getHeader(extensionClassname: extensionName), - Self.getFontNameEnum(fontsNames: fontsNames), - Self.getFontMethods(fontsNames: fontsNames, staticVar: staticVar), - Self.getFooter() - ] - .joined(separator: "\n") + let extensionContent = Self.getExtensionContent(fontsNames: fontsNames, + staticVar: staticVar, + extensionName: extensionName) // Write content let extensionFilePathURL = URL(fileURLWithPath: extensionFilePath) @@ -31,6 +27,16 @@ class FontExtensionGenerator { } } + static func getExtensionContent(fontsNames: [String], staticVar: Bool, extensionName: String) -> String { + [ + Self.getHeader(extensionClassname: extensionName), + Self.getFontNameEnum(fontsNames: fontsNames), + Self.getFontMethods(fontsNames: fontsNames, staticVar: staticVar), + Self.getFooter() + ] + .joined(separator: "\n") + } + private static func getHeader(extensionClassname: String) -> String { """ // Generated by ResgenSwift.\(Fonts.toolName) \(ResgenSwiftVersion) @@ -45,7 +51,7 @@ class FontExtensionGenerator { var enumDefinition = " enum FontName: String {\n" fontsNames.forEach { - enumDefinition += " case \($0.removeCharacters(from: "[]+-_")) = \"\($0)\"\n" + enumDefinition += " case \($0.fontNameSanitize) = \"\($0)\"\n" } enumDefinition += " }\n" diff --git a/Sources/ResgenSwift/Images/Generator/ImageExtensionGenerator.swift b/Sources/ResgenSwift/Images/Generator/ImageExtensionGenerator.swift index 73f6e4d..d5a9901 100644 --- a/Sources/ResgenSwift/Images/Generator/ImageExtensionGenerator.swift +++ b/Sources/ResgenSwift/Images/Generator/ImageExtensionGenerator.swift @@ -9,38 +9,20 @@ import ToolCore import Foundation class ImageExtensionGenerator { - - // MARK: - Extension files - - static func writeStringsFiles(images: [ParsedImage], staticVar: Bool, inputFilename: String, extensionName: String, extensionFilePath: String) { - // Get header/footer - let extensionHeader = Self.getHeader(inputFilename: inputFilename, extensionClassname: extensionName) - let extensionFooter = Self.getFooter() - - // Create content - let extensionContent: String = { - var content = "" - images.forEach { img in - if staticVar { - content += "\n\(img.getStaticImageProperty())" - } else { - content += "\n\(img.getImageProperty())" - } - content += "\n " - } - return content - }() - - // Generate extension - Self.generateExtensionFile(extensionFilePath: extensionFilePath, extensionHeader, extensionContent, extensionFooter) - } // MARK: - pragm - private static func generateExtensionFile(extensionFilePath: String, _ args: String...) { - // Create extension content - let extensionContent = args.joined(separator: "\n") - + static func generateExtensionFile(images: [ParsedImage], + staticVar: Bool, + inputFilename: String, + extensionName: String, + extensionFilePath: String) { + // Create extension conten1t + let extensionContent = Self.getExtensionContent(images: images, + staticVar: staticVar, + extensionName: extensionName, + inputFilename: inputFilename) + // Write content let extensionFilePathURL = URL(fileURLWithPath: extensionFilePath) do { @@ -52,9 +34,22 @@ class ImageExtensionGenerator { } } + // MARK: - Extension content + + static func getExtensionContent(images: [ParsedImage], staticVar: Bool, extensionName: String, inputFilename: String) -> String { + [ + Self.getHeader(inputFilename: inputFilename, extensionClassname: extensionName), + Self.getProperties(images: images, staticVar: staticVar), + Self.getFooter() + ] + .joined(separator: "\n") + } + + // MARK: - Extension part + private static func getHeader(inputFilename: String, extensionClassname: String) -> String { """ - // Generated by ResgenSwift.Imagium \(ResgenSwiftVersion) + // Generated by ResgenSwift.\(Images.toolName) \(ResgenSwiftVersion) // Images from \(inputFilename) import UIKit @@ -63,13 +58,20 @@ class ImageExtensionGenerator { """ } + private static func getProperties(images: [ParsedImage], staticVar: Bool) -> String { + if staticVar { + return images + .map { "\n\($0.getStaticImageProperty())" } + .joined(separator: "\n") + } + return images + .map { "\n\($0.getImageProperty())" } + .joined(separator: "\n") + } + private static func getFooter() -> String { """ } """ } } - -//@objc var onboarding_foreground3: UIImage { -// return UIImage(named: "onboarding_foreground3")! -// } diff --git a/Sources/ResgenSwift/Images/Images.swift b/Sources/ResgenSwift/Images/Images.swift index 0d26779..f419e06 100644 --- a/Sources/ResgenSwift/Images/Images.swift +++ b/Sources/ResgenSwift/Images/Images.swift @@ -52,11 +52,11 @@ struct Images: ParsableCommand { xcassetsPath: options.xcassetsPath) // Generate extension - ImageExtensionGenerator.writeStringsFiles(images: imagesToGenerate, - staticVar: options.staticMembers, - inputFilename: options.inputFilenameWithoutExt, - extensionName: options.extensionName, - extensionFilePath: options.extensionFilePath) + ImageExtensionGenerator.generateExtensionFile(images: imagesToGenerate, + staticVar: options.staticMembers, + inputFilename: options.inputFilenameWithoutExt, + extensionName: options.extensionName, + extensionFilePath: options.extensionFilePath) print("[\(Self.toolName)] Images generated") diff --git a/Sources/ResgenSwift/Images/Parser/ImageFileParser.swift b/Sources/ResgenSwift/Images/Parser/ImageFileParser.swift index 1b173fe..8a66d41 100644 --- a/Sources/ResgenSwift/Images/Parser/ImageFileParser.swift +++ b/Sources/ResgenSwift/Images/Parser/ImageFileParser.swift @@ -13,10 +13,13 @@ class ImageFileParser { let inputFileContent = try! String(contentsOfFile: inputFile, encoding: .utf8) let stringsByLines = inputFileContent.components(separatedBy: .newlines) + return Self.parseLines(stringsByLines, platform: platform) + } + + static func parseLines(_ lines: [String], platform: PlatormTag) -> [ParsedImage] { var imagesToGenerate = [ParsedImage]() - // Parse file - stringsByLines.forEach { + lines.forEach { guard $0.removeLeadingTrailingWhitespace().isEmpty == false, $0.first != "#" else { return } diff --git a/Sources/ResgenSwift/Strings/Generator/StringsFileGenerator.swift b/Sources/ResgenSwift/Strings/Generator/StringsFileGenerator.swift index 1ac694c..30f5009 100644 --- a/Sources/ResgenSwift/Strings/Generator/StringsFileGenerator.swift +++ b/Sources/ResgenSwift/Strings/Generator/StringsFileGenerator.swift @@ -37,7 +37,7 @@ class StringsFileGenerator { } } - private static func generateStringsFileContent(lang: String, defaultLang: String, tags inputTags: [String], sections: [Section]) -> String { + static func generateStringsFileContent(lang: String, defaultLang: String, tags inputTags: [String], sections: [Section]) -> String { var stringsFileContent = """ /** * Apple Strings File @@ -87,36 +87,13 @@ class StringsFileGenerator { // MARK: - Extension file static func writeExtensionFiles(sections: [Section], defaultLang lang: String, tags: [String], staticVar: Bool, inputFilename: String, extensionName: String, extensionFilePath: String) { - let extensionHeader = Self.getHeader(stringsFilename: inputFilename, extensionClassname: extensionName) - let extensionFooter = Self.getFooter() - - let extensionContent: String = { - var content = "" - sections.forEach { section in - // Check that at least one string will be generated - guard section.hasOneOrMoreMatchingTags(tags: tags) else { - return // Go to next section - } - - content += "\n // MARK: - \(section.name)" - section.definitions.forEach { definition in - guard definition.hasOneOrMoreMatchingTags(inputTags: tags) == true else { - return // Go to next definition - } - - if staticVar { - content += "\n\n\(definition.getNSLocalizedStringStaticProperty(forLang: lang))" - } else { - content += "\n\n\(definition.getNSLocalizedStringProperty(forLang: lang))" - } - } - content += "\n" - } - return content - }() - - // Create extension content - let extensionFileContent = [extensionHeader, extensionContent, extensionFooter].joined(separator: "\n") + // Get extension content + let extensionFileContent = Self.getExtensionContent(sections: sections, + defaultLang: lang, + tags: tags, + staticVar: staticVar, + inputFilename: inputFilename, + extensionName: extensionName) // Write content let extensionFilePathURL = URL(fileURLWithPath: extensionFilePath) @@ -129,6 +106,19 @@ class StringsFileGenerator { } } + // MARK: - Extension content + + static func getExtensionContent(sections: [Section], defaultLang lang: String, tags: [String], staticVar: Bool, inputFilename: String, extensionName: String) -> String { + [ + Self.getHeader(stringsFilename: inputFilename, extensionClassname: extensionName), + Self.getProperties(sections: sections, defaultLang: lang, tags: tags, staticVar: staticVar), + Self.getFooter() + ] + .joined(separator: "\n") + } + + // MARK: - Extension part + private static func getHeader(stringsFilename: String, extensionClassname: String) -> String { """ // Generated by ResgenSwift.Strings.\(Stringium.toolName) \(ResgenSwiftVersion) @@ -141,6 +131,30 @@ class StringsFileGenerator { """ } + private static func getProperties(sections: [Section], defaultLang lang: String, tags: [String], staticVar: Bool) -> String { + sections.compactMap { section in + // Check that at least one string will be generated + guard section.hasOneOrMoreMatchingTags(tags: tags) else { + return nil // Go to next section + } + + var res = "\n // MARK: - \(section.name)\n" + res += section.definitions.compactMap { definition in + guard definition.hasOneOrMoreMatchingTags(inputTags: tags) == true else { + return nil // Go to next definition + } + + if staticVar { + return "\n\(definition.getNSLocalizedStringStaticProperty(forLang: lang))" + } + return "\n\(definition.getNSLocalizedStringProperty(forLang: lang))" + } + .joined(separator: "\n") + return res + } + .joined(separator: "\n") + } + private static func getFooter() -> String { """ } diff --git a/Sources/ResgenSwift/Strings/Generator/TagsGenerator.swift b/Sources/ResgenSwift/Strings/Generator/TagsGenerator.swift index 888aafb..2756935 100644 --- a/Sources/ResgenSwift/Strings/Generator/TagsGenerator.swift +++ b/Sources/ResgenSwift/Strings/Generator/TagsGenerator.swift @@ -11,32 +11,12 @@ import CoreVideo class TagsGenerator { static func writeExtensionFiles(sections: [Section], lang: String, tags: [String], staticVar: Bool, extensionName: String, extensionFilePath: String) { - let extensionHeader = Self.getHeader(extensionClassname: extensionName, staticVar: staticVar) - let extensionFooter = Self.getFooter() - - let extensionContent: String = { - var content = "" - sections.forEach { section in - // Check that at least one string will be generated - guard section.hasOneOrMoreMatchingTags(tags: tags) else { - return // Go to next section - } - - content += "\n // MARK: - \(section.name)" - section.definitions.forEach { definition in - if staticVar { - content += "\n\n\(definition.getStaticProperty(forLang: lang))" - } else { - content += "\n\n\(definition.getProperty(forLang: lang))" - } - } - content += "\n" - } - return content - }() - - // Create extension content - let extensionFileContent = [extensionHeader, extensionContent, extensionFooter].joined(separator: "\n") + // Get extension content + let extensionFileContent = Self.getExtensionContent(sections: sections, + lang: lang, + tags: tags, + staticVar: staticVar, + extensionName: extensionName) // Write content let extensionFilePathURL = URL(fileURLWithPath: extensionFilePath) @@ -49,9 +29,22 @@ class TagsGenerator { } } + // MARK: - Extension content + + static func getExtensionContent(sections: [Section], lang: String, tags: [String], staticVar: Bool, extensionName: String) -> String { + [ + Self.getHeader(extensionClassname: extensionName, staticVar: staticVar), + Self.getProperties(sections: sections, lang: lang, tags: tags, staticVar: staticVar), + Self.getFooter() + ] + .joined(separator: "\n") + } + + // MARK: - Extension part + private static func getHeader(extensionClassname: String, staticVar: Bool) -> String { """ - // Generated by ResgenSwift.Strings.Tags \(ResgenSwiftVersion) + // Generated by ResgenSwift.Strings.\(Tags.toolName) \(ResgenSwiftVersion) \(staticVar ? "typelias Tags = String\n\n" : "")import UIKit @@ -59,6 +52,31 @@ class TagsGenerator { """ } + private static func getProperties(sections: [Section], lang: String, tags: [String], staticVar: Bool) -> String { + sections + .compactMap { section in + // Check that at least one string will be generated + guard section.hasOneOrMoreMatchingTags(tags: tags) else { + return nil// Go to next section + } + + var res = "\n // MARK: - \(section.name)" + section.definitions.forEach { definition in + guard definition.hasOneOrMoreMatchingTags(inputTags: tags) == true else { + return // Go to next definition + } + + if staticVar { + res += "\n\n\(definition.getStaticProperty(forLang: lang))" + } else { + res += "\n\n\(definition.getProperty(forLang: lang))" + } + } + return res + } + .joined(separator: "\n") + } + private static func getFooter() -> String { """ } diff --git a/Sources/ToolCore/StringExtensions.swift b/Sources/ToolCore/StringExtensions.swift index 47a7327..6d5077d 100644 --- a/Sources/ToolCore/StringExtensions.swift +++ b/Sources/ToolCore/StringExtensions.swift @@ -59,6 +59,7 @@ public extension String { } func replaceTiltWithHomeDirectoryPath() -> Self { + // See NSString.expandingTildeInPath replacingOccurrences(of: "~", with: "\(FileManager.default.homeDirectoryForCurrentUser.relativePath)") } diff --git a/Tests/ResgenSwiftTests/Colors/ColorExtensionGeneratorTests.swift b/Tests/ResgenSwiftTests/Colors/ColorExtensionGeneratorTests.swift new file mode 100644 index 0000000..54bbded --- /dev/null +++ b/Tests/ResgenSwiftTests/Colors/ColorExtensionGeneratorTests.swift @@ -0,0 +1,85 @@ +// +// ColorExtensionGeneratorTests.swift +// +// +// Created by Thibaut Schmitt on 05/09/2022. +// + +import Foundation +import XCTest +import ToolCore + +@testable import ResgenSwift + +final class ColorExtensionGeneratorTests: XCTestCase { + + func testGeneratedExtensionContent() { + // Given + let colors = [ + ParsedColor(name: "colorOne", light: "#FF00FF", dark: "#00FF00"), + ParsedColor(name: "colorTwo", light: "#F0F0F0", dark: "#0F0F0F") + ] + + // When + let extensionContent = ColorExtensionGenerator.getExtensionContent(colors: colors, + staticVar: false, + extensionName: "GenColors") + + // Expect + let expect = """ + // Generated by ResgenSwift.Color \(ResgenSwiftVersion) + + import UIKit + + extension GenColors { + + /// Color colorOne is #FF00FF (light) or #00FF00 (dark)" + @objc var colorOne: UIColor { + UIColor(named: "colorOne")! + } + + /// Color colorTwo is #F0F0F0 (light) or #0F0F0F (dark)" + @objc var colorTwo: UIColor { + UIColor(named: "colorTwo")! + } + } + """ + + XCTAssertEqual(extensionContent.adaptForXCTest(), expect.adaptForXCTest()) + } + + func testGeneratedExtensionContentForStaticVar() { + // Given + let colors = [ + ParsedColor(name: "colorOne", light: "#FF00FF", dark: "#00FF00"), + ParsedColor(name: "colorTwo", light: "#F0F0F0", dark: "#0F0F0F") + ] + + // When + let extensionContent = ColorExtensionGenerator.getExtensionContent(colors: colors, + staticVar: true, + extensionName: "GenColor") + + // Expect + let expect = """ + // Generated by ResgenSwift.Color \(ResgenSwiftVersion) + + import UIKit + + extension GenColor { + + /// Color colorOne is #FF00FF (light) or #00FF00 (dark)" + static var colorOne: UIColor { + UIColor(named: "colorOne")! + } + + /// Color colorTwo is #F0F0F0 (light) or #0F0F0F (dark)" + static var colorTwo: UIColor { + UIColor(named: "colorTwo")! + } + } + """ + + XCTAssertEqual(extensionContent.adaptForXCTest(), expect.adaptForXCTest()) + } +} diff --git a/Tests/ResgenSwiftTests/Colors/ColorFileParserTests.swift b/Tests/ResgenSwiftTests/Colors/ColorFileParserTests.swift new file mode 100644 index 0000000..69f3ff3 --- /dev/null +++ b/Tests/ResgenSwiftTests/Colors/ColorFileParserTests.swift @@ -0,0 +1,98 @@ +// +// ColorFileParserTests.swift +// +// +// Created by Thibaut Schmitt on 05/09/2022. +// + +import Foundation +import XCTest + +@testable import ResgenSwift + +final class ColorFileParserTests: XCTestCase { + func testCorrectFormat_lightStyle() throws { + // Given + let inputWithEqualSeparator = """ + red1 = #FF0000 + red2 = #FFFF0000 + + red3 = #FF0000 + red4 = #FFFF0000 + + red5 = #FF0000 #0000FF + red6 = #FFFF0000 #FF0000FF + """ + .components(separatedBy: CharacterSet.newlines) + + let inputWithSpaceSeparator = """ + red1 #FF0000 + red2 #FFFF0000 + + red3 #FF0000 + red4 #FFFF0000 + + red5 #FF0000 #0000FF + red6 #FFFF0000 #FF0000FF + """ + .components(separatedBy: CharacterSet.newlines) + + // When + let colorsFromEqual = ColorFileParser.parseLines(lines: inputWithEqualSeparator, + colorStyle: .light) + let colorsFromSpace = ColorFileParser.parseLines(lines: inputWithSpaceSeparator, + colorStyle: .light) + + // Expect + let colorsValues: [(name: String, light: String, dark: String)] = [ + (name: "red1", light: "#FF0000", dark: "#FF0000"), + (name: "red2", light: "#FFFF0000", dark: "#FFFF0000"), + (name: "red3", light: "#FF0000", dark: "#FF0000"), + (name: "red4", light: "#FFFF0000", dark: "#FFFF0000"), + (name: "red5", light: "#FF0000", dark: "#FF0000"), + (name: "red6", light: "#FFFF0000", dark: "#FFFF0000"), + ] + + + var foundColors = 0 + let allParsedColors = colorsFromEqual + colorsFromSpace + for parsedColor in allParsedColors { + let testValues = colorsValues.first { $0.name == parsedColor.name } + if let testValues = testValues { + foundColors += 1 + XCTAssertEqual(parsedColor.name, testValues.name) + XCTAssertEqual(parsedColor.light, testValues.light) + XCTAssertEqual(parsedColor.dark, testValues.dark) + } + } + + XCTAssertEqual(foundColors, 12) + } + + func testCorrectFormat_allColorStyle() throws { + // Given + let input = """ + lightOnly #FF0000 + lightDark #FF0000 #0000FF + """ + .components(separatedBy: CharacterSet.newlines) + + // When + let parsedColors = ColorFileParser.parseLines(lines: input, + colorStyle: .all) + + // Expect + let colorRed1 = parsedColors.first { $0.name == "lightOnly" } + let colorRed2 = parsedColors.first { $0.name == "lightDark" } + + XCTAssertNotNil(colorRed1) + XCTAssertEqual(colorRed1?.name, "lightOnly") + XCTAssertEqual(colorRed1?.light, "#FF0000") + XCTAssertEqual(colorRed1?.dark, "#FF0000") + + XCTAssertNotNil(colorRed2) + XCTAssertEqual(colorRed2?.name, "lightDark") + XCTAssertEqual(colorRed2?.light, "#FF0000") + XCTAssertEqual(colorRed2?.dark, "#0000FF") + } +} diff --git a/Tests/ResgenSwiftTests/Colors/ParsedColorTests.swift b/Tests/ResgenSwiftTests/Colors/ParsedColorTests.swift new file mode 100644 index 0000000..ec1f16c --- /dev/null +++ b/Tests/ResgenSwiftTests/Colors/ParsedColorTests.swift @@ -0,0 +1,91 @@ +// +// ParsedColorTests.swift +// +// +// Created by Thibaut Schmitt on 05/09/2022. +// + +import Foundation +import XCTest + +@testable import ResgenSwift + +final class ParsedColorTests: XCTestCase { + + func testGeneratedProperty() { + // Given + let color = ParsedColor(name: "red", light: "#FF0000", dark: "#0000FF") + + // When + let property = color.getColorProperty() + + // Expect + let expect = """ + /// Color red is #FF0000 (light) or #0000FF (dark)" + @objc var red: UIColor { + UIColor(named: "red")! + } + """ + + XCTAssertEqual(property.adaptForXCTest(), expect.adaptForXCTest()) + } + + func testGeneratedStaticProperty() { + // Given + let color = ParsedColor(name: "red", light: "#FF0000", dark: "#0000FF") + + // When + let property = color.getColorStaticProperty() + + // Expect + let expect = """ + /// Color red is #FF0000 (light) or #0000FF (dark)" + static var red: UIColor { + UIColor(named: "red")! + } + """ + + XCTAssertEqual(property.adaptForXCTest(), expect.adaptForXCTest()) + } + + func testGeneratedColorAsset() { + // Given + let color = ParsedColor(name: "red", light: "#FF0000", dark: "#0000FF") + + // When + let contentJson = color.contentsJSON() + guard let data = contentJson.data(using: .utf8), + let parsedJson = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { + XCTFail("Cannot convert `contentJSON` string to Data") + return + } + + let colors = parsedJson["colors"] as! [Any] + + for color in colors { + guard let color = color as? [String: Any] else { + XCTFail("Cannot convert color object to Dictonnary") + return + } + if let appearance = color["appearances"] as? [Any] { + // Appearance is define only for dark appearance + let firstAppearance = appearance.first! as! [String: Any] + XCTAssertEqual(firstAppearance["value"] as! String, "dark") + + let subColor = color["color"] as! [String: Any] + let components = subColor["components"] as! [String: Any] + XCTAssertEqual(components["alpha"] as! String, "0xFF") + XCTAssertEqual(components["blue"] as! String, "0xFF") + XCTAssertEqual(components["green"] as! String, "0x00") + XCTAssertEqual(components["red"] as! String, "0x00") + } else { + let subColor = color["color"] as! [String: Any] + let components = subColor["components"] as! [String: Any] + XCTAssertEqual(components["alpha"] as! String, "0xFF") + XCTAssertEqual(components["blue"] as! String, "0x00") + XCTAssertEqual(components["green"] as! String, "0x00") + XCTAssertEqual(components["red"] as! String, "0xFF") + } + } + } +} diff --git a/Tests/ResgenSwiftTests/Extensions/StringExtensions.swift b/Tests/ResgenSwiftTests/Extensions/StringExtensions.swift new file mode 100644 index 0000000..e1a97ca --- /dev/null +++ b/Tests/ResgenSwiftTests/Extensions/StringExtensions.swift @@ -0,0 +1,19 @@ +// +// StringExtensions.swift +// +// +// Created by Thibaut Schmitt on 05/09/2022. +// + +import Foundation + +extension String { + + /// Remove all new lines and leading/trailing whitespaces + func adaptForXCTest() -> Self { + self + .split(separator: "\n") + .compactMap { String($0).removeLeadingTrailingWhitespace() } + .joined(separator: " - ") + } +} diff --git a/Tests/ResgenSwiftTests/Fonts/FontExtensionGeneratorTests.swift b/Tests/ResgenSwiftTests/Fonts/FontExtensionGeneratorTests.swift new file mode 100644 index 0000000..8ea70f1 --- /dev/null +++ b/Tests/ResgenSwiftTests/Fonts/FontExtensionGeneratorTests.swift @@ -0,0 +1,57 @@ +// +// FontExtensionGeneratorTests.swift +// +// +// Created by Thibaut Schmitt on 05/09/2022. +// + +import Foundation +import XCTest +import ToolCore + +@testable import ResgenSwift + +final class FontExtensionGeneratorTests: XCTestCase { + + func testGeneratedExtensionContent() { + // Given + let fontNames: [FontName] = [ + "CircularStd-Regular", + "CircularStd-Bold" + ] + + // When + let extensionContent = FontExtensionGenerator.getExtensionContent(fontsNames: fontNames, + staticVar: false, + extensionName: "GenFonts") + + // Expect + let expect = """ + // Generated by ResgenSwift.Fonts \(ResgenSwiftVersion) + + import UIKit + + extension GenFonts { + + enum FontName: String { + case CircularStdRegular = "CircularStd-Regular" + case CircularStdBold = "CircularStd-Bold" + } + + // MARK: - Getter + + func CircularStdRegular(withSize size: CGFloat) -> UIFont { + UIFont(name: FontName.CircularStdRegular.rawValue, size: size)! + } + + func CircularStdBold(withSize size: CGFloat) -> UIFont { + UIFont(name: FontName.CircularStdBold.rawValue, size: size)! + } + + } + """ + + XCTAssertEqual(extensionContent.adaptForXCTest(), expect.adaptForXCTest()) + } + +} diff --git a/Tests/ResgenSwiftTests/Fonts/FontNameTests.swift b/Tests/ResgenSwiftTests/Fonts/FontNameTests.swift new file mode 100644 index 0000000..03a09a2 --- /dev/null +++ b/Tests/ResgenSwiftTests/Fonts/FontNameTests.swift @@ -0,0 +1,83 @@ +// +// FontNameTests.swift +// +// +// Created by Thibaut Schmitt on 05/09/2022. +// + +import Foundation +import XCTest + +@testable import ResgenSwift + +final class FontNameTests: XCTestCase { + + func testGeneratedProperty_noForbiddenCharacter() { + // Given + let fontName: FontName = "CircularStdBold" + + // When + let property = fontName.staticProperty + + // Expect + let expect = """ + static let CircularStdBold: ((_ size: CGFloat) -> UIFont) = { size in + UIFont(name: FontName.CircularStdBold.rawValue, size: size)! + } + """ + + XCTAssertEqual(property.adaptForXCTest(), expect.adaptForXCTest()) + } + + func testGeneratedProperty_withForbiddenCharacter() { + // Given + let fontName: FontName = "[Circular_Std+Bold-Underline]" + + // When + let property = fontName.staticProperty + + // Expect + let expect = """ + static let CircularStdBoldUnderline: ((_ size: CGFloat) -> UIFont) = { size in + UIFont(name: FontName.CircularStdBoldUnderline.rawValue, size: size)! + } + """ + + XCTAssertEqual(property.adaptForXCTest(), expect.adaptForXCTest()) + } + + func testGeneratedMethod_noForbiddenCharacter() { + // Given + let fontName: FontName = "CircularStdBold" + + // When + let property = fontName.method + + // Expect + let expect = """ + func CircularStdBold(withSize size: CGFloat) -> UIFont { + UIFont(name: FontName.CircularStdBold.rawValue, size: size)! + } + """ + + XCTAssertEqual(property.adaptForXCTest(), expect.adaptForXCTest()) + } + + func testGeneratedMethod_withForbiddenCharacter() { + // Given + let fontName: FontName = "[Circular_Std+Bold-Underline]" + + // When + let property = fontName.method + + // Expect + let expect = """ + func CircularStdBoldUnderline(withSize size: CGFloat) -> UIFont { + UIFont(name: FontName.CircularStdBoldUnderline.rawValue, size: size)! + } + """ + + XCTAssertEqual(property.adaptForXCTest(), expect.adaptForXCTest()) + } + +} diff --git a/Tests/ResgenSwiftTests/Fonts/FontPlistGeneratorTests.swift b/Tests/ResgenSwiftTests/Fonts/FontPlistGeneratorTests.swift new file mode 100644 index 0000000..0bab9f0 --- /dev/null +++ b/Tests/ResgenSwiftTests/Fonts/FontPlistGeneratorTests.swift @@ -0,0 +1,35 @@ +// +// FontPlistGeneratorTests.swift +// +// +// Created by Thibaut Schmitt on 05/09/2022. +// + +import Foundation +import XCTest + +@testable import ResgenSwift + +final class FontPlistGeneratorTests: XCTestCase { + func testGeneratedPlist() { + // Given + let fontNames: [FontName] = [ + "CircularStd-Regular", + "CircularStd-Bold" + ] + + // When + let plistContent = FontPlistGenerator.generatePlistUIAppsFontContent(for: fontNames) + + // Expect + let expect = """ + UIAppFonts + + CircularStd-Regular + CircularStd-Bold + + """ + + XCTAssertEqual(plistContent.adaptForXCTest(), expect.adaptForXCTest()) + } +} diff --git a/Tests/ResgenSwiftTests/Images/ImageExtensionGeneratorTests.swift b/Tests/ResgenSwiftTests/Images/ImageExtensionGeneratorTests.swift new file mode 100644 index 0000000..c8bf707 --- /dev/null +++ b/Tests/ResgenSwiftTests/Images/ImageExtensionGeneratorTests.swift @@ -0,0 +1,85 @@ +// +// ImageExtensionGeneratorTests.swift +// +// +// Created by Thibaut Schmitt on 05/09/2022. +// + +import Foundation +import XCTest +import ToolCore + +@testable import ResgenSwift + +final class ImageExtensionGeneratorTests: XCTestCase { + + func testGeneratedExtensionContent() { + // Given + let images = [ + ParsedImage(name: "image_one", tags: "id", width: 10, height: 10), + ParsedImage(name: "image_two", tags: "id", width: 180, height: 90), + ] + + // When + let extensionContent = ImageExtensionGenerator.getExtensionContent(images: images, + staticVar: false, + extensionName: "GenImages", + inputFilename: "myInputFilename") + + // Expect + let expect = """ + // Generated by ResgenSwift.Images \(ResgenSwiftVersion) + // Images from myInputFilename + + import UIKit + + extension GenImages { + + var image_one: UIImage { + UIImage(named: "image_one")! + } + + var image_two: UIImage { + UIImage(named: "image_two")! + } + } + """ + + XCTAssertEqual(extensionContent.adaptForXCTest(), expect.adaptForXCTest()) + } + + func testGeneratedExtensionContentForStaticVar() { + // Given + let images = [ + ParsedImage(name: "image_one", tags: "id", width: 10, height: 10), + ParsedImage(name: "image_two", tags: "id", width: 180, height: 90), + ] + + // When + let extensionContent = ImageExtensionGenerator.getExtensionContent(images: images, + staticVar: true, + extensionName: "GenImages", + inputFilename: "myInputFilename") + + // Expect + let expect = """ + // Generated by ResgenSwift.Images \(ResgenSwiftVersion) + // Images from myInputFilename + + import UIKit + + extension GenImages { + + static var image_one: UIImage { + UIImage(named: "image_one")! + } + + static var image_two: UIImage { + UIImage(named: "image_two")! + } + } + """ + + XCTAssertEqual(extensionContent.adaptForXCTest(), expect.adaptForXCTest()) + } +} diff --git a/Tests/ResgenSwiftTests/Images/ImageFileParserTests.swift b/Tests/ResgenSwiftTests/Images/ImageFileParserTests.swift new file mode 100644 index 0000000..0dad2e6 --- /dev/null +++ b/Tests/ResgenSwiftTests/Images/ImageFileParserTests.swift @@ -0,0 +1,50 @@ +// +// ImageFileParserTests.swift +// +// +// Created by Thibaut Schmitt on 05/09/2022. +// + +import Foundation +import XCTest + +@testable import ResgenSwift + +class ImageFileParserTests: XCTestCase { + func testParseImagesFile() { + // Given + let input = """ + # + # SMAAS Support + # + id image_one 25 ? + di image_two ? 50 + d image_three 25 ? + d image_four 75 ? + """ + .components(separatedBy: CharacterSet.newlines) + + // When + let parsedImages = ImageFileParser.parseLines(input, + platform: PlatormTag.ios) + + // Expect + XCTAssertEqual(parsedImages.count, 2) + + let firstImage = parsedImages.first { + $0.name == "image_one" + } + XCTAssertEqual(firstImage!.name, "image_one") + XCTAssertEqual(firstImage!.tags, "id") + XCTAssertEqual(firstImage!.width, 25) + XCTAssertEqual(firstImage!.height, -1) + + let secondImage = parsedImages.first { + $0.name == "image_two" + } + XCTAssertEqual(secondImage!.name, "image_two") + XCTAssertEqual(secondImage!.tags, "di") + XCTAssertEqual(secondImage!.width, -1) + XCTAssertEqual(secondImage!.height, 50) + } +} diff --git a/Tests/ResgenSwiftTests/Images/ParsedImageTests.swift b/Tests/ResgenSwiftTests/Images/ParsedImageTests.swift new file mode 100644 index 0000000..a45be87 --- /dev/null +++ b/Tests/ResgenSwiftTests/Images/ParsedImageTests.swift @@ -0,0 +1,119 @@ +// +// ParsedImage.swift +// +// +// Created by Thibaut Schmitt on 05/09/2022. +// + +import Foundation +import XCTest + +@testable import ResgenSwift + +final class ParsedImageTests: XCTestCase { + + func testConvertArguments() { + // Given + let imageName = "the_name" + let parsedImage = ParsedImage(name: imageName, + tags: "id", + width: 10, + height: 10) + + // When + let convertArguments = parsedImage.convertArguments + + // Expect + XCTAssertEqual(convertArguments.x1.width, "10") + XCTAssertEqual(convertArguments.x1.height, "10") + + XCTAssertEqual(convertArguments.x2.width, "20") + XCTAssertEqual(convertArguments.x2.height, "20") + + XCTAssertEqual(convertArguments.x3.width, "30") + XCTAssertEqual(convertArguments.x3.height, "30") + } + + func testGeneratedProperty() { + // Given + let imageName = "the_name" + let parsedImage = ParsedImage(name: imageName, + tags: "id", + width: 10, + height: 10) + + // When + let property = parsedImage.getImageProperty() + + // Expect + let expect = """ + var \(imageName): UIImage { + UIImage(named: "\(imageName)")! + } + """ + + XCTAssertEqual(property.adaptForXCTest(), expect.adaptForXCTest()) + } + + func testGeneratedStaticProperty() { + // Given + let imageName = "the_name" + let parsedImage = ParsedImage(name: imageName, + tags: "id", + width: 10, + height: 10) + + // When + let property = parsedImage.getStaticImageProperty() + + // Expect + let expect = """ + static var \(imageName): UIImage { + UIImage(named: "\(imageName)")! + } + """ + + XCTAssertEqual(property.adaptForXCTest(), expect.adaptForXCTest()) + } + + func testAssetContentJson() { + // Given + let imageName = "the_name" + let parsedImage = ParsedImage(name: imageName, + tags: "id", + width: 10, + height: 10) + + // When + let property = parsedImage.contentJson + + // Expect + let expect = """ + { + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "\(imageName).\(XcassetsGenerator.outputImageExtension)" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "\(imageName)@2x.\(XcassetsGenerator.outputImageExtension)" + }, + { + "idiom" : "universal", + "scale" : "3x", + "filename" : "\(imageName)@3x.\(XcassetsGenerator.outputImageExtension)" + } + ], + "info" : { + "version" : 1, + "author" : "ResgenSwift-Imagium" + } + } + """ + + XCTAssertEqual(property.adaptForXCTest(), expect.adaptForXCTest()) + } +} diff --git a/Tests/ResgenSwiftTests/ResgenSwiftTests.swift b/Tests/ResgenSwiftTests/ResgenSwiftTests.swift index 0fe94aa..508d37b 100644 --- a/Tests/ResgenSwiftTests/ResgenSwiftTests.swift +++ b/Tests/ResgenSwiftTests/ResgenSwiftTests.swift @@ -1,6 +1,8 @@ import XCTest import class Foundation.Bundle +@testable import ResgenSwift + final class ResgenCLITests: XCTestCase { func testExample() throws { // This is an example of a functional test case. diff --git a/Tests/ResgenSwiftTests/Strings/DefinitionTests.swift b/Tests/ResgenSwiftTests/Strings/DefinitionTests.swift new file mode 100644 index 0000000..f61087a --- /dev/null +++ b/Tests/ResgenSwiftTests/Strings/DefinitionTests.swift @@ -0,0 +1,374 @@ +// +// DefinitionTests.swift +// +// +// Created by Thibaut Schmitt on 06/09/2022. +// + +import Foundation +import XCTest + +@testable import ResgenSwift + +final class DefinitionTests: XCTestCase { + + // MARK: - Match line + + func testMatchingDefinition() { + // Given + let line = "[definition_name]" + + // When + let definition = Definition.match(line) + + // Expect + XCTAssertNotNil(definition) + XCTAssertEqual(definition?.name, "definition_name") + } + + func testNotMatchingDefinition() { + // Given + let line1 = "definition_name" + let line2 = "[definition_name" + let line3 = "definition_name]" + + // When + let definition1 = Definition.match(line1) + let definition2 = Definition.match(line2) + let definition3 = Definition.match(line3) + + // Expect + XCTAssertNil(definition1) + XCTAssertNil(definition2) + XCTAssertNil(definition3) + } + + // MARK: - Matching tags + + func testMatchingTags() { + // Given + let definition = Definition(name: "definition_name") + definition.tags = ["ios","iosonly","notranslation"] + + // When + let match1 = definition.hasOneOrMoreMatchingTags(inputTags: ["ios"]) + let match2 = definition.hasOneOrMoreMatchingTags(inputTags: ["iosonly"]) + let match3 = definition.hasOneOrMoreMatchingTags(inputTags: ["notranslation"]) + + + // Expect + XCTAssertTrue(match1) + XCTAssertTrue(match2) + XCTAssertTrue(match3) + } + + func testNotMatchingTags() { + // Given + let definition = Definition(name: "definition_name") + definition.tags = ["ios","iosonly","notranslation"] + + // When + let match1 = definition.hasOneOrMoreMatchingTags(inputTags: ["droid"]) + let match2 = definition.hasOneOrMoreMatchingTags(inputTags: ["droidonly"]) + let match3 = definition.hasOneOrMoreMatchingTags(inputTags: ["azerty"]) + + // Expect + XCTAssertFalse(match1) + XCTAssertFalse(match2) + XCTAssertFalse(match3) + } + + // MARK: - getNSLocalizedStringProperty + + func testGeneratedNSLocalizedStringProperty() { + // Given + let definition = Definition(name: "definition_name") + definition.tags = ["ios","iosonly","notranslation"] + definition.comment = "This is a comment" + definition.translations = [ + "fr": "C'est la traduction francaise", + "en": "This is the english translation", + "en-us": "This is the english us translation" + ] + + // When + let propertyFr = definition.getNSLocalizedStringProperty(forLang: "fr") + let propertyEn = definition.getNSLocalizedStringProperty(forLang: "en") + let propertyEnUs = definition.getNSLocalizedStringProperty(forLang: "en-us") + + // Expect + let expectFr = """ + /// Translation in fr : + /// C'est la traduction francaise + var definition_name: String { + NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "C'est la traduction francaise", comment: "") + } + """ + + let expectEn = """ + /// Translation in en : + /// This is the english translation + var definition_name: String { + NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "This is the english translation", comment: "") + } + """ + + let expectEnUs = """ + /// Translation in en-us : + /// This is the english us translation + var definition_name: String { + NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "This is the english us translation", comment: "") + } + """ + + XCTAssertEqual(propertyFr.adaptForXCTest(), expectFr.adaptForXCTest()) + XCTAssertEqual(propertyEn.adaptForXCTest(), expectEn.adaptForXCTest()) + XCTAssertEqual(propertyEnUs.adaptForXCTest(), expectEnUs.adaptForXCTest()) + } + + func testGeneratedNSLocalizedStringStaticProperty() { + // Given + let definition = Definition(name: "definition_name") + definition.tags = ["ios","iosonly","notranslation"] + definition.comment = "This is a comment" + definition.translations = [ + "fr": "C'est la traduction francaise", + "en": "This is the english translation", + "en-us": "This is the english us translation" + ] + + // When + let propertyFr = definition.getNSLocalizedStringStaticProperty(forLang: "fr") + let propertyEn = definition.getNSLocalizedStringStaticProperty(forLang: "en") + let propertyEnUs = definition.getNSLocalizedStringStaticProperty(forLang: "en-us") + + // Expect + let expectFr = """ + /// Translation in fr : + /// C'est la traduction francaise + static var definition_name: String { + NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "C'est la traduction francaise", comment: "") + } + """ + + let expectEn = """ + /// Translation in en : + /// This is the english translation + static var definition_name: String { + NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "This is the english translation", comment: "") + } + """ + + let expectEnUs = """ + /// Translation in en-us : + /// This is the english us translation + static var definition_name: String { + NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "This is the english us translation", comment: "") + } + """ + + XCTAssertEqual(propertyFr.adaptForXCTest(), expectFr.adaptForXCTest()) + XCTAssertEqual(propertyEn.adaptForXCTest(), expectEn.adaptForXCTest()) + XCTAssertEqual(propertyEnUs.adaptForXCTest(), expectEnUs.adaptForXCTest()) + } + + func testGeneratedNSLocalizedStringPropertyWithOneArgument() { + // Given + let definition = Definition(name: "definition_name") + definition.tags = ["ios","iosonly","notranslation"] + definition.comment = "This is a comment" + definition.translations = [ + "fr": "Welcome \"%@\" !" + ] + + // When + let propertyFr = definition.getNSLocalizedStringProperty(forLang: "fr") + + // Expect + let expectFr = """ + /// Translation in fr : + /// Welcome "%@" ! + var definition_name: String { + NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "Welcome \"%@\" !", comment: "") + } + + /// Translation in fr : + /// Welcome "%@" ! + func definition_name(arg0: String) -> String { + String(format: self.definition_name, arg0) + } + """ + + XCTAssertEqual(propertyFr.adaptForXCTest(), expectFr.adaptForXCTest()) + } + + func testGeneratedNSLocalizedStringPropertyWithMultipleArgument() { + // Given + let definition = Definition(name: "definition_name") + definition.tags = ["ios","iosonly","notranslation"] + definition.comment = "This is a comment" + definition.translations = [ + "fr": "Welcome \"%@\" ! Your age is %d :) Your weight is %f ;-)" + ] + + // When + let propertyFr = definition.getNSLocalizedStringProperty(forLang: "fr") + + // Expect + let expectFr = """ + /// Translation in fr : + /// Welcome "%@" ! Your age is %d :) Your weight is %f ;-) + var definition_name: String { + NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "Welcome \"%@\" ! Your age is %d :) Your weight is %f ;-)", comment: "") + } + + /// Translation in fr : + /// Welcome "%@" ! Your age is %d :) Your weight is %f ;-) + func definition_name(arg0: String, arg1: Int, arg2: Double) -> String { + String(format: self.definition_name, arg0, arg1, arg2) + } + """ + + XCTAssertEqual(propertyFr.adaptForXCTest(), expectFr.adaptForXCTest()) + } + + func testGeneratedNSLocalizedStringPropertyWithNumberedArguments() { + // Given + let definition = Definition(name: "definition_name") + definition.tags = ["ios","iosonly","notranslation"] + definition.comment = "This is a comment" + definition.translations = [ + "fr": "Vous %%: %1$@ %2$@ Age: %3$d", + "en": "You %%: %2$@ %1$@ Age: %3$d" + ] + + // When + let propertyFr = definition.getNSLocalizedStringProperty(forLang: "fr") + let propertyEn = definition.getNSLocalizedStringProperty(forLang: "en") + + let expectFr = """ + /// Translation in fr : + /// Vous %%: %1$@ %2$@ Age: %3$d + var definition_name: String { + NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "Vous %%: %1$@ %2$@ Age: %3$d", comment: "") + } + + /// Translation in fr : + /// Vous %%: %1$@ %2$@ Age: %3$d + func definition_name(arg0: String, arg1: String, arg2: Int) -> String { + String(format: self.definition_name, arg0, arg1, arg2) + } + """ + + let expectEn = """ + /// Translation in en : + /// You %%: %2$@ %1$@ Age: %3$d + var definition_name: String { + NSLocalizedString("definition_name", tableName: kStringsFileName, bundle: Bundle.main, value: "You %%: %2$@ %1$@ Age: %3$d", comment: "") + } + + /// Translation in en : + /// You %%: %2$@ %1$@ Age: %3$d + func definition_name(arg0: String, arg1: String, arg2: Int) -> String { + String(format: self.definition_name, arg0, arg1, arg2) + } + """ + + XCTAssertEqual(propertyFr.adaptForXCTest(), expectFr.adaptForXCTest()) + XCTAssertEqual(propertyEn.adaptForXCTest(), expectEn.adaptForXCTest()) + } + + // MARK: - Raw properties + + func testGeneratedRawProperty() { + // Given + let definition = Definition(name: "definition_name") + definition.tags = ["ios","iosonly","notranslation"] + definition.comment = "This is a comment" + definition.translations = [ + "fr": "C'est la traduction francaise", + "en": "This is the english translation", + "en-us": "This is the english us translation" + ] + + // When + let propertyFr = definition.getProperty(forLang: "fr") + let propertyEn = definition.getProperty(forLang: "en") + let propertyEnUs = definition.getProperty(forLang: "en-us") + + // Expect + let expectFr = """ + /// Translation in fr : + /// C'est la traduction francaise + var definition_name: String { + "C'est la traduction francaise" + } + """ + + let expectEn = """ + /// Translation in en : + /// This is the english translation + var definition_name: String { + "This is the english translation" + } + """ + + let expectEnUs = """ + /// Translation in en-us : + /// This is the english us translation + var definition_name: String { + "This is the english us translation" + } + """ + + XCTAssertEqual(propertyFr.adaptForXCTest(), expectFr.adaptForXCTest()) + XCTAssertEqual(propertyEn.adaptForXCTest(), expectEn.adaptForXCTest()) + XCTAssertEqual(propertyEnUs.adaptForXCTest(), expectEnUs.adaptForXCTest()) + } + + func testGeneratedRawStaticProperty() { + // Given + let definition = Definition(name: "definition_name") + definition.tags = ["ios","iosonly","notranslation"] + definition.comment = "This is a comment" + definition.translations = [ + "fr": "C'est la traduction francaise", + "en": "This is the english translation", + "en-us": "This is the english us translation" + ] + + // When + let propertyFr = definition.getStaticProperty(forLang: "fr") + let propertyEn = definition.getStaticProperty(forLang: "en") + let propertyEnUs = definition.getStaticProperty(forLang: "en-us") + + // Expect + let expectFr = """ + /// Translation in fr : + /// C'est la traduction francaise + static var definition_name: String { + "C'est la traduction francaise" + } + """ + + let expectEn = """ + /// Translation in en : + /// This is the english translation + static var definition_name: String { + "This is the english translation" + } + """ + + let expectEnUs = """ + /// Translation in en-us : + /// This is the english us translation + static var definition_name: String { + "This is the english us translation" + } + """ + + XCTAssertEqual(propertyFr.adaptForXCTest(), expectFr.adaptForXCTest()) + XCTAssertEqual(propertyEn.adaptForXCTest(), expectEn.adaptForXCTest()) + XCTAssertEqual(propertyEnUs.adaptForXCTest(), expectEnUs.adaptForXCTest()) + } +} diff --git a/Tests/ResgenSwiftTests/Strings/SectionTests.swift b/Tests/ResgenSwiftTests/Strings/SectionTests.swift new file mode 100644 index 0000000..d848349 --- /dev/null +++ b/Tests/ResgenSwiftTests/Strings/SectionTests.swift @@ -0,0 +1,104 @@ +// +// SectionTests.swift +// +// +// Created by Thibaut Schmitt on 06/09/2022. +// + +import Foundation +import XCTest + +@testable import ResgenSwift + +final class SectionTests: XCTestCase { + + // MARK: - Match line + + func testMatchingDefinition() { + // Given + let line = "[[section_name]]" + + // When + let section = Section.match(line) + + // Expect + XCTAssertNotNil(section) + XCTAssertEqual(section?.name, "section_name") + } + + func testNotMatchingDefinition() { + // Given + let lines = ["section_name", + "[section_name]", + "[section_name", + "[[section_name", + "[[section_name]", + "section_name]", + "section_name]]", + "[section_name]]"] + + // When + let matches = lines.compactMap { Section.match($0) } + + // Expect + XCTAssertEqual(matches.isEmpty, true) + } + + // MARK: - Matching tags + + func testMatchingTags() { + // Given + let section = Section(name: "section_name") + section.definitions = [ + { + let def = Definition(name: "definition_name") + def.tags = ["ios","iosonly"] + return def + }(), + { + let def = Definition(name: "definition_name_two") + def.tags = ["droid","droidonly"] + return def + }() + ] + + // When + let match1 = section.hasOneOrMoreMatchingTags(tags: ["ios"]) + let match2 = section.hasOneOrMoreMatchingTags(tags: ["iosonly"]) + let match3 = section.hasOneOrMoreMatchingTags(tags: ["droid"]) + let match4 = section.hasOneOrMoreMatchingTags(tags: ["droidonly"]) + + // Expect + XCTAssertTrue(match1) + XCTAssertTrue(match2) + XCTAssertTrue(match3) + XCTAssertTrue(match4) + } + + func testNotMatchingTags() { + // Given + let section = Section(name: "section_name") + section.definitions = [ + { + let def = Definition(name: "definition_name") + def.tags = ["ios","iosonly"] + return def + }(), + { + let def = Definition(name: "definition_name_two") + def.tags = ["droid","droidonly"] + return def + }() + ] + + // When + let match1 = section.hasOneOrMoreMatchingTags(tags: ["web"]) + let match2 = section.hasOneOrMoreMatchingTags(tags: ["webonly"]) + let match3 = section.hasOneOrMoreMatchingTags(tags: ["azerty"]) + + // Expect + XCTAssertFalse(match1) + XCTAssertFalse(match2) + XCTAssertFalse(match3) + } +} diff --git a/Tests/ResgenSwiftTests/Strings/StringsFileGeneratorTests.swift b/Tests/ResgenSwiftTests/Strings/StringsFileGeneratorTests.swift new file mode 100644 index 0000000..5740bd5 --- /dev/null +++ b/Tests/ResgenSwiftTests/Strings/StringsFileGeneratorTests.swift @@ -0,0 +1,255 @@ +// +// StringsFileGeneratorTests.swift +// +// +// Created by Thibaut Schmitt on 06/09/2022. +// + +import Foundation +import XCTest +import ToolCore + +@testable import ResgenSwift + +final class StringsFileGeneratorTests: XCTestCase { + + private func getDefinition(name: String, translations: [String: String], tags: [String]) -> Definition { + let definition = Definition(name: name) + definition.tags = tags + definition.translations = translations + return definition + } + + func testGenerateStringsFileContent() { + // Given + let sectionOne = Section(name: "section_one") + sectionOne.definitions = [ + getDefinition(name: "s1_def_one", + translations: ["fr": "Section Un - Definition Un", + "en": "Section One - Definition One"], + tags: ["ios","iosonly"]), + getDefinition(name: "s1_def_two", + translations: ["fr": "Section Un - Definition Deux", + "en": "Section One - Definition Two"], + tags: ["ios","iosonly"]) + ] + + let sectionTwo = Section(name: "section_two") + sectionTwo.definitions = [ + getDefinition(name: "s2_def_one", + translations: ["fr": "Section Deux - Definition Un", + "en": "Section Two - Definition One"], + tags: ["ios","iosonly"]), + getDefinition(name: "s2_def_two", + translations: ["fr": "Section Deux - Definition Deux"], + tags: ["notranslation"]) + ] + + // When + let stringsFileContentFr = StringsFileGenerator.generateStringsFileContent(lang: "fr", + defaultLang: "fr", + tags: ["ios", "iosonly", "notranslation"], + sections: [sectionOne, sectionTwo]) + let stringsFileContentEn = StringsFileGenerator.generateStringsFileContent(lang: "en", + defaultLang: "fr", + tags: ["ios", "iosonly", "notranslation"], + sections: [sectionOne, sectionTwo]) + + // Expect + let expectFr = """ + /** + * Apple Strings File + * Generated by ResgenSwift \(ResgenSwiftVersion) + * Language: fr + */ + + /********** section_one **********/ + + "s1_def_one" = "Section Un - Definition Un"; + + "s1_def_two" = "Section Un - Definition Deux"; + + /********** section_two **********/ + + "s2_def_one" = "Section Deux - Definition Un"; + + "s2_def_two" = "Section Deux - Definition Deux"; + """ + + let expectEn = """ + /** + * Apple Strings File + * Generated by ResgenSwift \(ResgenSwiftVersion) + * Language: en + */ + + /********** section_one **********/ + + "s1_def_one" = "Section One - Definition One"; + + "s1_def_two" = "Section One - Definition Two"; + + /********** section_two **********/ + + "s2_def_one" = "Section Two - Definition One"; + + "s2_def_two" = "Section Deux - Definition Deux"; + """ + + XCTAssertEqual(stringsFileContentFr.adaptForXCTest(), expectFr.adaptForXCTest()) + XCTAssertEqual(stringsFileContentEn.adaptForXCTest(), expectEn.adaptForXCTest()) + } + + func testGeneratedExtensionContent() { + // Given + let sectionOne = Section(name: "section_one") + sectionOne.definitions = [ + getDefinition(name: "s1_def_one", + translations: ["fr": "Section Un - Definition Un", + "en": "Section One - Definition One"], + tags: ["ios","iosonly"]), + getDefinition(name: "s1_def_two", + translations: ["fr": "Section Un - Definition Deux", + "en": "Section One - Definition Two"], + tags: ["ios","iosonly"]) + ] + + let sectionTwo = Section(name: "section_two") + sectionTwo.definitions = [ + getDefinition(name: "s2_def_one", + translations: ["fr": "Section Deux - Definition Un", + "en": "Section Two - Definition One"], + tags: ["ios","iosonly"]), + getDefinition(name: "s2_def_two", + translations: ["fr": "Section Deux - Definition Deux"], + tags: ["notranslation"]) + ] + + // When + let extensionContent = StringsFileGenerator.getExtensionContent(sections: [sectionOne, sectionTwo], + defaultLang: "fr", + tags: ["ios", "iosonly", "notranslation"], + staticVar: false, + inputFilename: "myInputFilename", + extensionName: "GenStrings") + + // Expect + let expect = """ + // Generated by ResgenSwift.Strings.Stringium \(ResgenSwiftVersion) + + import UIKit + + fileprivate let kStringsFileName = "myInputFilename" + + extension GenStrings { + + // MARK: - section_one + + /// Translation in fr : + /// Section Un - Definition Un + var s1_def_one: String { + NSLocalizedString("s1_def_one", tableName: kStringsFileName, bundle: Bundle.main, value: "Section Un - Definition Un", comment: "") + } + + /// Translation in fr : + /// Section Un - Definition Deux + var s1_def_two: String { + NSLocalizedString("s1_def_two", tableName: kStringsFileName, bundle: Bundle.main, value: "Section Un - Definition Deux", comment: "") + } + + // MARK: - section_two + + /// Translation in fr : + /// Section Deux - Definition Un + var s2_def_one: String { + NSLocalizedString("s2_def_one", tableName: kStringsFileName, bundle: Bundle.main, value: "Section Deux - Definition Un", comment: "") + } + + /// Translation in fr : + /// Section Deux - Definition Deux + var s2_def_two: String { + NSLocalizedString("s2_def_two", tableName: kStringsFileName, bundle: Bundle.main, value: "Section Deux - Definition Deux", comment: "") + } + } + """ + + XCTAssertEqual(extensionContent.adaptForXCTest(), expect.adaptForXCTest()) + } + + func testGeneratedExtensionContentWithStaticVar() { + // Given + let sectionOne = Section(name: "section_one") + sectionOne.definitions = [ + getDefinition(name: "s1_def_one", + translations: ["fr": "Section Un - Definition Un", + "en": "Section One - Definition One"], + tags: ["ios","iosonly"]), + getDefinition(name: "s1_def_two", + translations: ["fr": "Section Un - Definition Deux", + "en": "Section One - Definition Two"], + tags: ["ios","iosonly"]) + ] + + let sectionTwo = Section(name: "section_two") + sectionTwo.definitions = [ + getDefinition(name: "s2_def_one", + translations: ["fr": "Section Deux - Definition Un", + "en": "Section Two - Definition One"], + tags: ["ios","iosonly"]), + getDefinition(name: "s2_def_two", + translations: ["fr": "Section Deux - Definition Deux"], + tags: ["notranslation"]) + ] + + // When + let extensionContent = StringsFileGenerator.getExtensionContent(sections: [sectionOne, sectionTwo], + defaultLang: "fr", + tags: ["ios", "iosonly", "notranslation"], + staticVar: true, + inputFilename: "myInputFilename", + extensionName: "GenStrings") + + // Expect + let expect = """ + // Generated by ResgenSwift.Strings.Stringium \(ResgenSwiftVersion) + + import UIKit + + fileprivate let kStringsFileName = "myInputFilename" + + extension GenStrings { + + // MARK: - section_one + + /// Translation in fr : + /// Section Un - Definition Un + static var s1_def_one: String { + NSLocalizedString("s1_def_one", tableName: kStringsFileName, bundle: Bundle.main, value: "Section Un - Definition Un", comment: "") + } + + /// Translation in fr : + /// Section Un - Definition Deux + static var s1_def_two: String { + NSLocalizedString("s1_def_two", tableName: kStringsFileName, bundle: Bundle.main, value: "Section Un - Definition Deux", comment: "") + } + + // MARK: - section_two + + /// Translation in fr : + /// Section Deux - Definition Un + static var s2_def_one: String { + NSLocalizedString("s2_def_one", tableName: kStringsFileName, bundle: Bundle.main, value: "Section Deux - Definition Un", comment: "") + } + + /// Translation in fr : + /// Section Deux - Definition Deux + static var s2_def_two: String { + NSLocalizedString("s2_def_two", tableName: kStringsFileName, bundle: Bundle.main, value: "Section Deux - Definition Deux", comment: "") + } + } + """ + + XCTAssertEqual(extensionContent.adaptForXCTest(), expect.adaptForXCTest()) + } +} + diff --git a/Tests/ResgenSwiftTests/Strings/TagsGeneratorTests.swift b/Tests/ResgenSwiftTests/Strings/TagsGeneratorTests.swift new file mode 100644 index 0000000..561c70c --- /dev/null +++ b/Tests/ResgenSwiftTests/Strings/TagsGeneratorTests.swift @@ -0,0 +1,82 @@ +// +// TagsGeneratorTests.swift +// +// +// Created by Thibaut Schmitt on 06/09/2022. +// + +import Foundation +import XCTest +import ToolCore + +@testable import ResgenSwift + +final class TagsGeneratorTests: XCTestCase { + + private func getDefinition(name: String, lang: String, tags: [String]) -> Definition { + let definition = Definition(name: name) + definition.tags = tags + definition.translations = [lang: "Some translation"] + return definition + } + + func testGeneratedExtensionContent() { + // Given + let sectionOne = Section(name: "section_one") + sectionOne.definitions = [ + getDefinition(name: "s1_def_one", lang: "ium", tags: ["ios","iosonly"]), + getDefinition(name: "s1_def_two", lang: "ium", tags: ["ios","iosonly"]), + ] + + let sectionTwo = Section(name: "section_two") + sectionTwo.definitions = [ + getDefinition(name: "s2_def_one", lang: "ium", tags: ["ios","iosonly"]), + getDefinition(name: "s2_def_two", lang: "ium", tags: ["droid","droidonly"]) + ] + + let sectionThree = Section(name: "section_three") + sectionThree.definitions = [ + getDefinition(name: "s3_def_one", lang: "ium", tags: ["droid","droidonly"]), + getDefinition(name: "s3_def_two", lang: "ium", tags: ["droid","droidonly"]) + ] + + // When + let extensionContent = TagsGenerator.getExtensionContent(sections: [sectionOne, sectionTwo, sectionThree], + lang: "ium", + tags: ["ios", "iosonly"], + staticVar: false, + extensionName: "GenTags") + // Expect Tags + let expect = """ + // Generated by ResgenSwift.Strings.Tags \(ResgenSwiftVersion) + + import UIKit + + extension GenTags { + // MARK: - section_one + + /// Translation in ium : + /// Some translation + var s1_def_one: String { + "Some translation" + } + + /// Translation in ium : + /// Some translation + var s1_def_two: String { + "Some translation" + } + + // MARK: - section_two + + /// Translation in ium : + /// Some translation + var s2_def_one: String { + "Some translation" + } + } + """ + + XCTAssertEqual(extensionContent.adaptForXCTest(), expect.adaptForXCTest()) + } +}