diff --git a/Sources/ResgenSwift/Tags/Generator/TagsGenerator.swift b/Sources/ResgenSwift/Tags/Generator/TagsGenerator.swift index f5f7fce..e803a69 100644 --- a/Sources/ResgenSwift/Tags/Generator/TagsGenerator.swift +++ b/Sources/ResgenSwift/Tags/Generator/TagsGenerator.swift @@ -126,13 +126,13 @@ class TagsGenerator { let footer = " }" if targets.contains(Tags.TargetType.matomo) { - header = "func configure(sideId: String, url: String) {" + header = "func configure(siteId: String, url: String) {" } else if targets.contains(Tags.TargetType.firebase) { header = "func configure() {" } if targets.contains(Tags.TargetType.matomo) { - content.append(" managers.append(MatomoAnalyticsManager(siteId: sideId, url: url))\n") + content.append(" managers.append(MatomoAnalyticsManager(siteId: siteId, url: url))") } if targets.contains(Tags.TargetType.firebase) { content.append(" managers.append(FirebaseAnalyticsManager())") diff --git a/Tests/ResgenSwiftTests/Strings/StringsFileGeneratorTests.swift b/Tests/ResgenSwiftTests/Strings/StringsFileGeneratorTests.swift index 5d3193c..764e5af 100644 --- a/Tests/ResgenSwiftTests/Strings/StringsFileGeneratorTests.swift +++ b/Tests/ResgenSwiftTests/Strings/StringsFileGeneratorTests.swift @@ -144,6 +144,22 @@ final class StringsFileGeneratorTests: XCTestCase { extension GenStrings { + enum KeyStrings: String { + case s1_def_one = "s1_def_one" + case s1_def_two = "s1_def_two" + case s2_def_one = "s2_def_one" + case s2_def_two = "s2_def_two" + + var keyPath: KeyPath { + switch self { + case .s1_def_one: return \\GenStrings.s1_def_one + case .s1_def_two: return \\GenStrings.s1_def_two + case .s2_def_one: return \\GenStrings.s2_def_one + case .s2_def_two: return \\GenStrings.s2_def_two + } + } + } + // MARK: - section_one /// Translation in fr : @@ -174,6 +190,9 @@ final class StringsFileGeneratorTests: XCTestCase { } """ + if extensionContent != expect { + print(prettyFirstDifferenceBetweenStrings(s1: extensionContent, s2: expect)) + } XCTAssertEqual(extensionContent.adaptForXCTest(), expect.adaptForXCTest()) } @@ -221,6 +240,22 @@ final class StringsFileGeneratorTests: XCTestCase { extension GenStrings { + enum KeyStrings: String { + case s1_def_one = "s1_def_one" + case s1_def_two = "s1_def_two" + case s2_def_one = "s2_def_one" + case s2_def_two = "s2_def_two" + + var keyPath: KeyPath { + switch self { + case .s1_def_one: return \\GenStrings.s1_def_one + case .s1_def_two: return \\GenStrings.s1_def_two + case .s2_def_one: return \\GenStrings.s2_def_one + case .s2_def_two: return \\GenStrings.s2_def_two + } + } + } + // MARK: - section_one /// Translation in fr : @@ -251,6 +286,9 @@ final class StringsFileGeneratorTests: XCTestCase { } """ + if extensionContent != expect { + print(prettyFirstDifferenceBetweenStrings(s1: extensionContent, s2: expect)) + } XCTAssertEqual(extensionContent.adaptForXCTest(), expect.adaptForXCTest()) } } diff --git a/Tests/ResgenSwiftTests/Strings/TagsGeneratorTests.swift b/Tests/ResgenSwiftTests/Strings/TagsGeneratorTests.swift deleted file mode 100644 index 619f587..0000000 --- a/Tests/ResgenSwiftTests/Strings/TagsGeneratorTests.swift +++ /dev/null @@ -1,82 +0,0 @@ -// -// 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]) -> TagDefinition { - let definition = TagDefinition(title: name) - definition.tags = tags -// definition.translations = [lang: "Some translation"] - return definition - } - - func testGeneratedExtensionContent() { - // Given - let sectionOne = TagSection(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 = TagSection(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 = TagSection(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], - targets: [Tags.TargetType.firebase], - 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()) - } -} diff --git a/Tests/ResgenSwiftTests/Tags/DiffString.swift b/Tests/ResgenSwiftTests/Tags/DiffString.swift new file mode 100644 index 0000000..60f41cf --- /dev/null +++ b/Tests/ResgenSwiftTests/Tags/DiffString.swift @@ -0,0 +1,135 @@ +// +// File.swift +// +// +// Created by Loris Perret on 06/12/2023. +// + +import Foundation + + +/// Find first differing character between two strings +/// +/// :param: s1 First String +/// :param: s2 Second String +/// +/// :returns: .DifferenceAtIndex(i) or .NoDifference +public func firstDifferenceBetweenStrings(s1: NSString, s2: NSString) -> FirstDifferenceResult { + let len1 = s1.length + let len2 = s2.length + + let lenMin = min(len1, len2) + + for i in 0.. String { + let firstDifferenceResult = firstDifferenceBetweenStrings(s1: s1 as NSString, s2: s2 as NSString) + return prettyDescriptionOfFirstDifferenceResult(firstDifferenceResult: firstDifferenceResult, s1: s1 as NSString, s2: s2 as NSString) as String +} + + +/// Create a formatted String representation of a FirstDifferenceResult for two strings +/// +/// :param: firstDifferenceResult FirstDifferenceResult +/// :param: s1 First string used in generation of firstDifferenceResult +/// :param: s2 Second string used in generation of firstDifferenceResult +/// +/// :returns: a printable string, possibly containing significant whitespace and newlines +public func prettyDescriptionOfFirstDifferenceResult(firstDifferenceResult: FirstDifferenceResult, s1: NSString, s2: NSString) -> NSString { + + func diffString(index: Int, s1: NSString, s2: NSString) -> NSString { + let markerArrow = "\u{2b06}" // "⬆" + let ellipsis = "\u{2026}" // "…" + /// Given a string and a range, return a string representing that substring. + /// + /// If the range starts at a position other than 0, an ellipsis + /// will be included at the beginning. + /// + /// If the range ends before the actual end of the string, + /// an ellipsis is added at the end. + func windowSubstring(s: NSString, range: NSRange) -> String { + let validRange = NSMakeRange(range.location, min(range.length, s.length - range.location)) + let substring = s.substring(with: validRange) + + let prefix = range.location > 0 ? ellipsis : "" + let suffix = (s.length - range.location > range.length) ? ellipsis : "" + + return "\(prefix)\(substring)\(suffix)" + } + + // Show this many characters before and after the first difference + let windowPrefixLength = 10 + let windowSuffixLength = 10 + let windowLength = windowPrefixLength + 1 + windowSuffixLength + + let windowIndex = max(index - windowPrefixLength, 0) + let windowRange = NSMakeRange(windowIndex, windowLength) + + let sub1 = windowSubstring(s: s1, range: windowRange) + let sub2 = windowSubstring(s: s2, range: windowRange) + + let markerPosition = min(windowSuffixLength, index) + (windowIndex > 0 ? 1 : 0) + + let markerPrefix = String(repeating: " " as Character, count: markerPosition) + let markerLine = "\(markerPrefix)\(markerArrow)" + + return "Difference at index \(index):\n\(sub1)\n\(sub2)\n\(markerLine)" as NSString + } + + switch firstDifferenceResult { + case .NoDifference: return "No difference" + case .DifferenceAtIndex(let index): return diffString(index: index, s1: s1, s2: s2) + } +} + + +/// Result type for firstDifferenceBetweenStrings() +public enum FirstDifferenceResult { + /// Strings are identical + case NoDifference + + /// Strings differ at the specified index. + /// + /// This could mean that characters at the specified index are different, + /// or that one string is longer than the other + case DifferenceAtIndex(Int) +} + +extension FirstDifferenceResult { + /// Textual representation of a FirstDifferenceResult + public var description: String { + switch self { + case .NoDifference: + return "NoDifference" + case .DifferenceAtIndex(let index): + return "DifferenceAtIndex(\(index))" + } + } + + /// Textual representation of a FirstDifferenceResult for debugging purposes + public var debugDescription: String { + return self.description + } +} diff --git a/Tests/ResgenSwiftTests/Tags/TagDefinitionTests.swift b/Tests/ResgenSwiftTests/Tags/TagDefinitionTests.swift new file mode 100644 index 0000000..9a9d116 --- /dev/null +++ b/Tests/ResgenSwiftTests/Tags/TagDefinitionTests.swift @@ -0,0 +1,162 @@ +// +// TagDefinitionTests.swift +// +// +// Created by Loris Perret on 06/12/2023. +// + +import Foundation +import XCTest + +@testable import ResgenSwift + +final class TagDefinitionTests: XCTestCase { + + // MARK: - Match line + + func testMatchingTagDefinition() { + // Given + let line = "[definition_name]" + + // When + let definition = TagDefinition.match(line) + + // Expect + XCTAssertNotNil(definition) + XCTAssertEqual(definition?.title, "definition_name") + } + + func testNotMatchingTagDefinition() { + // Given + let line1 = "definition_name" + let line2 = "[definition_name" + let line3 = "definition_name]" + + // When + let definition1 = TagDefinition.match(line1) + let definition2 = TagDefinition.match(line2) + let definition3 = TagDefinition.match(line3) + + // Expect + XCTAssertNil(definition1) + XCTAssertNil(definition2) + XCTAssertNil(definition3) + } + + // MARK: - Matching tags + + func testMatchingTags() { + // Given + let definition = TagDefinition(title: "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 = TagDefinition(title: "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: - Raw properties + + func testGeneratedRawPropertyScreen() { + // Given + let definition = TagDefinition(title: "definition_name") + definition.path = "ecran_un/" + definition.name = "Ecran un" + definition.type = "screen" + + // When + let propertyScreen = definition.getProperty() + + // Expect + let expectScreen = """ + func logScreenEcranUn() { + logScreen(name: "Ecran un", path: "ecran_un/") + } + """ + + XCTAssertEqual(propertyScreen.adaptForXCTest(), expectScreen.adaptForXCTest()) + } + + func testGeneratedRawPropertyEvent() { + // Given + let definition = TagDefinition(title: "definition_name") + definition.path = "ecran_un/" + definition.name = "Ecran un" + definition.type = "event" + + // When + let propertyEvent = definition.getProperty() + + // Expect + let expectEvent = """ + func logEventEcranUn() { + logEvent(name: "Ecran un") + } + """ + + XCTAssertEqual(propertyEvent.adaptForXCTest(), expectEvent.adaptForXCTest()) + } + + func testGeneratedRawStaticPropertyScreen() { + // Given + let definition = TagDefinition(title: "definition_name") + definition.path = "ecran_un/" + definition.name = "Ecran un" + definition.type = "screen" + + // When + let propertyScreen = definition.getStaticProperty() + + // Expect + let expectScreen = """ + static func logScreenEcranUn() { + logScreen(name: "Ecran un", path: "ecran_un/") + } + """ + + XCTAssertEqual(propertyScreen.adaptForXCTest(), expectScreen.adaptForXCTest()) + } + + func testGeneratedRawStaticPropertyEvent() { + // Given + let definition = TagDefinition(title: "definition_name") + definition.path = "ecran_un/" + definition.name = "Ecran un" + definition.type = "event" + + // When + let propertyEvent = definition.getStaticProperty() + + // Expect + let expectEvent = """ + static func logEventEcranUn() { + logEvent(name: "Ecran un") + } + """ + + XCTAssertEqual(propertyEvent.adaptForXCTest(), expectEvent.adaptForXCTest()) + } +} diff --git a/Tests/ResgenSwiftTests/Tags/TagSectionTests.swift b/Tests/ResgenSwiftTests/Tags/TagSectionTests.swift new file mode 100644 index 0000000..979fe38 --- /dev/null +++ b/Tests/ResgenSwiftTests/Tags/TagSectionTests.swift @@ -0,0 +1,104 @@ +// +// TagSectionTests.swift +// +// +// Created by Loris Perret on 06/12/2023. +// + +import Foundation +import XCTest + +@testable import ResgenSwift + +final class TagSectionTests: XCTestCase { + + // MARK: - Match line + + func testMatchingTagSection() { + // Given + let line = "[[section_name]]" + + // When + let section = TagSection.match(line) + + // Expect + XCTAssertNotNil(section) + XCTAssertEqual(section?.name, "section_name") + } + + func testNotMatchingTagSection() { + // Given + let lines = ["section_name", + "[section_name]", + "[section_name", + "[[section_name", + "[[section_name]", + "section_name]", + "section_name]]", + "[section_name]]"] + + // When + let matches = lines.compactMap { TagSection.match($0) } + + // Expect + XCTAssertEqual(matches.isEmpty, true) + } + + // MARK: - Matching tags + + func testMatchingTags() { + // Given + let section = TagSection(name: "section_name") + section.definitions = [ + { + let def = TagDefinition(title: "definition_name") + def.tags = ["ios","iosonly"] + return def + }(), + { + let def = TagDefinition(title: "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 = TagSection(name: "section_name") + section.definitions = [ + { + let def = TagDefinition(title: "definition_name") + def.tags = ["ios","iosonly"] + return def + }(), + { + let def = TagDefinition(title: "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/Tags/TagsGeneratorTests.swift b/Tests/ResgenSwiftTests/Tags/TagsGeneratorTests.swift new file mode 100644 index 0000000..b10dfb5 --- /dev/null +++ b/Tests/ResgenSwiftTests/Tags/TagsGeneratorTests.swift @@ -0,0 +1,454 @@ +// +// 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 getTagDefinition(title: String, path: String, name: String, type: String, tags: [String]) -> TagDefinition { + let definition = TagDefinition(title: title) + definition.path = path + definition.name = name + definition.type = type + definition.tags = tags + return definition + } + + func testGeneratedExtensionContentFirebase() { + // Given + let sectionOne = TagSection(name: "section_one") + sectionOne.definitions = [ + getTagDefinition(title: "s1_def_one", path: "s1_def_one/", name: "s1 def one", type: "screen", tags: ["ios", "iosonly"]), + getTagDefinition(title: "s1_def_two", path: "s1_def_two/", name: "s1 def two", type: "event", tags: ["ios", "iosonly"]), + ] + + let sectionTwo = TagSection(name: "section_two") + sectionTwo.definitions = [ + getTagDefinition(title: "s2_def_one", path: "s2_def_one/", name: "s2 def one", type: "screen", tags: ["ios","iosonly"]), + getTagDefinition(title: "s2_def_two", path: "s2_def_two/", name: "s2 def two", type: "event", tags: ["droid","droidonly"]), + ] + + let sectionThree = TagSection(name: "section_three") + sectionThree.definitions = [ + getTagDefinition(title: "s3_def_one", path: "s3_def_one/", name: "s3 def one", type: "screen", tags: ["droid","droidonly"]), + getTagDefinition(title: "s3_def_two", path: "s3_def_two/", name: "s3 def two", type: "event", tags: ["droid","droidonly"]), + ] + + // When + TagsGenerator.targets = [Tags.TargetType.firebase] + let extensionContent = TagsGenerator.getExtensionContent(sections: [sectionOne, sectionTwo, sectionThree], + tags: ["ios", "iosonly"], + staticVar: false, + extensionName: "GenTags") + // Expect Tags + let expect = """ + // Generated by ResgenSwift.Tags 1.2 + + import UIKit + import Firebase + + // MARK: - Protocol + + protocol AnalyticsManagerProtocol { + func logScreen(name: String, path: String) + func logEvent(name: String) + } + + // MARK: - Firebase + + class FirebaseAnalyticsManager: AnalyticsManagerProtocol { + func logScreen(name: String, path: String) { + Analytics.logEvent(AnalyticsEventScreenView, parameters: [AnalyticsParameterScreenName: name]) + } + + func logEvent(name: String) { + var parameters = [ + AnalyticsParameterValue: name + ] + + Analytics.logEvent(AnalyticsEventSelectContent, parameters: parameters) + } + } + + // MARK: - Manager + + class AnalyticsManager { + static var shared = AnalyticsManager() + + // MARK: - Properties + + var managers: [AnalyticsManagerProtocol] = [] + + private var isEnabled: Bool = true + + // MARK: - Methods + + func setAnalyticsEnabled(_ enable: Bool) { isEnabled = enable } + + func configure() { + managers.append(FirebaseAnalyticsManager()) + } + + private func logScreen(name: String, path: String) { + guard isEnabled else { return } + managers.forEach { manager in + manager.logScreen(name: name, path: path) + } + } + + private func logEvent(name: String) { + guard isEnabled else { return } + managers.forEach { manager in + manager.logEvent(name: name) + } + } + + // MARK: - section_one + + func logScreenS1DefOne() { + logScreen(name: "s1 def one", path: "s1_def_one/") + } + + func logEventS1DefTwo() { + logEvent(name: "s1 def two") + } + + // MARK: - section_two + + func logScreenS2DefOne() { + logScreen(name: "s2 def one", path: "s2_def_one/") + } + } + + """ + + if extensionContent != expect { + print(prettyFirstDifferenceBetweenStrings(s1: extensionContent, s2: expect)) + } + XCTAssertEqual(extensionContent.adaptForXCTest(), expect.adaptForXCTest()) + } + + func testGeneratedExtensionContentMatomo() { + // Given + let sectionOne = TagSection(name: "section_one") + sectionOne.definitions = [ + getTagDefinition(title: "s1_def_one", path: "s1_def_one/", name: "s1 def one", type: "screen", tags: ["ios", "iosonly"]), + getTagDefinition(title: "s1_def_two", path: "s1_def_two/", name: "s1 def two", type: "event", tags: ["ios", "iosonly"]), + ] + + let sectionTwo = TagSection(name: "section_two") + sectionTwo.definitions = [ + getTagDefinition(title: "s2_def_one", path: "s2_def_one/", name: "s2 def one", type: "screen", tags: ["ios","iosonly"]), + getTagDefinition(title: "s2_def_two", path: "s2_def_two/", name: "s2 def two", type: "event", tags: ["droid","droidonly"]), + ] + + let sectionThree = TagSection(name: "section_three") + sectionThree.definitions = [ + getTagDefinition(title: "s3_def_one", path: "s3_def_one/", name: "s3 def one", type: "screen", tags: ["droid","droidonly"]), + getTagDefinition(title: "s3_def_two", path: "s3_def_two/", name: "s3 def two", type: "event", tags: ["droid","droidonly"]), + ] + + // When + TagsGenerator.targets = [Tags.TargetType.matomo] + let extensionContent = TagsGenerator.getExtensionContent(sections: [sectionOne, sectionTwo, sectionThree], + tags: ["ios", "iosonly"], + staticVar: false, + extensionName: "GenTags") + // Expect Tags + let expect = """ + // Generated by ResgenSwift.Tags 1.2 + + import UIKit + import MatomoTracker + + // MARK: - Protocol + + protocol AnalyticsManagerProtocol { + func logScreen(name: String, path: String) + func logEvent(name: String) + } + + // MARK: - Matomo + + class MatomoAnalyticsManager: AnalyticsManagerProtocol { + + // MARK: - Properties + + private var tracker: MatomoTracker + + // MARK: - Init + + init(siteId: String, url: String) { + debugPrint("[Matomo service] Server URL: \\(url)") + debugPrint("[Matomo service] Site ID: \\(siteId)") + tracker = MatomoTracker(siteId: siteId, baseURL: URL(string: url)!) + + #if DEBUG + tracker.dispatchInterval = 5 + #endif + + #if DEBUG + tracker.logger = DefaultLogger(minLevel: .verbose) + #endif + + debugPrint("[Matomo service] Configured with content base: \\(tracker.contentBase?.absoluteString ?? "-")") + debugPrint("[Matomo service] Opt out: \\(tracker.isOptedOut)") + } + + // MARK: - Methods + + func logScreen(name: String, path: String) { + guard !tracker.isOptedOut else { return } + guard let trackerUrl = tracker.contentBase?.absoluteString else { return } + let urlString = URL(string: "\\(trackerUrl)" + "/" + "\\(path)" + "iOS") + tracker.track( + view: [name], + url: urlString + ) + } + + func logEvent(name: String) { + guard !tracker.isOptedOut else { return } + tracker.track( + eventWithCategory: "category", + action: "action", + name: name, + number: nil, + url: nil + ) + } + } + + // MARK: - Manager + + class AnalyticsManager { + static var shared = AnalyticsManager() + + // MARK: - Properties + + var managers: [AnalyticsManagerProtocol] = [] + + private var isEnabled: Bool = true + + // MARK: - Methods + + func setAnalyticsEnabled(_ enable: Bool) { isEnabled = enable } + + func configure(siteId: String, url: String) { + managers.append(MatomoAnalyticsManager(siteId: siteId, url: url)) + } + + private func logScreen(name: String, path: String) { + guard isEnabled else { return } + managers.forEach { manager in + manager.logScreen(name: name, path: path) + } + } + + private func logEvent(name: String) { + guard isEnabled else { return } + managers.forEach { manager in + manager.logEvent(name: name) + } + } + + // MARK: - section_one + + func logScreenS1DefOne() { + logScreen(name: "s1 def one", path: "s1_def_one/") + } + + func logEventS1DefTwo() { + logEvent(name: "s1 def two") + } + + // MARK: - section_two + + func logScreenS2DefOne() { + logScreen(name: "s2 def one", path: "s2_def_one/") + } + } + + """ + + if extensionContent != expect { + print(prettyFirstDifferenceBetweenStrings(s1: extensionContent, s2: expect)) + } + XCTAssertEqual(extensionContent.adaptForXCTest(), expect.adaptForXCTest()) + } + + func testGeneratedExtensionContentMatomoAndFirebase() { + // Given + let sectionOne = TagSection(name: "section_one") + sectionOne.definitions = [ + getTagDefinition(title: "s1_def_one", path: "s1_def_one/", name: "s1 def one", type: "screen", tags: ["ios", "iosonly"]), + getTagDefinition(title: "s1_def_two", path: "s1_def_two/", name: "s1 def two", type: "event", tags: ["ios", "iosonly"]), + ] + + let sectionTwo = TagSection(name: "section_two") + sectionTwo.definitions = [ + getTagDefinition(title: "s2_def_one", path: "s2_def_one/", name: "s2 def one", type: "screen", tags: ["ios","iosonly"]), + getTagDefinition(title: "s2_def_two", path: "s2_def_two/", name: "s2 def two", type: "event", tags: ["droid","droidonly"]), + ] + + let sectionThree = TagSection(name: "section_three") + sectionThree.definitions = [ + getTagDefinition(title: "s3_def_one", path: "s3_def_one/", name: "s3 def one", type: "screen", tags: ["droid","droidonly"]), + getTagDefinition(title: "s3_def_two", path: "s3_def_two/", name: "s3 def two", type: "event", tags: ["droid","droidonly"]), + ] + + // When + TagsGenerator.targets = [Tags.TargetType.matomo, Tags.TargetType.firebase] + let extensionContent = TagsGenerator.getExtensionContent(sections: [sectionOne, sectionTwo, sectionThree], + tags: ["ios", "iosonly"], + staticVar: false, + extensionName: "GenTags") + // Expect Tags + let expect = """ + // Generated by ResgenSwift.Tags 1.2 + + import UIKit + import MatomoTracker + import Firebase + + // MARK: - Protocol + + protocol AnalyticsManagerProtocol { + func logScreen(name: String, path: String) + func logEvent(name: String) + } + + // MARK: - Matomo + + class MatomoAnalyticsManager: AnalyticsManagerProtocol { + + // MARK: - Properties + + private var tracker: MatomoTracker + + // MARK: - Init + + init(siteId: String, url: String) { + debugPrint("[Matomo service] Server URL: \\(url)") + debugPrint("[Matomo service] Site ID: \\(siteId)") + tracker = MatomoTracker(siteId: siteId, baseURL: URL(string: url)!) + + #if DEBUG + tracker.dispatchInterval = 5 + #endif + + #if DEBUG + tracker.logger = DefaultLogger(minLevel: .verbose) + #endif + + debugPrint("[Matomo service] Configured with content base: \\(tracker.contentBase?.absoluteString ?? "-")") + debugPrint("[Matomo service] Opt out: \\(tracker.isOptedOut)") + } + + // MARK: - Methods + + func logScreen(name: String, path: String) { + guard !tracker.isOptedOut else { return } + guard let trackerUrl = tracker.contentBase?.absoluteString else { return } + let urlString = URL(string: "\\(trackerUrl)" + "/" + "\\(path)" + "iOS") + tracker.track( + view: [name], + url: urlString + ) + } + + func logEvent(name: String) { + guard !tracker.isOptedOut else { return } + tracker.track( + eventWithCategory: "category", + action: "action", + name: name, + number: nil, + url: nil + ) + } + } + + // MARK: - Firebase + + class FirebaseAnalyticsManager: AnalyticsManagerProtocol { + func logScreen(name: String, path: String) { + Analytics.logEvent(AnalyticsEventScreenView, parameters: [AnalyticsParameterScreenName: name]) + } + + func logEvent(name: String) { + var parameters = [ + AnalyticsParameterValue: name + ] + + Analytics.logEvent(AnalyticsEventSelectContent, parameters: parameters) + } + } + + // MARK: - Manager + + class AnalyticsManager { + static var shared = AnalyticsManager() + + // MARK: - Properties + + var managers: [AnalyticsManagerProtocol] = [] + + private var isEnabled: Bool = true + + // MARK: - Methods + + func setAnalyticsEnabled(_ enable: Bool) { isEnabled = enable } + + func configure(siteId: String, url: String) { + managers.append(MatomoAnalyticsManager(siteId: siteId, url: url)) + managers.append(FirebaseAnalyticsManager()) + } + + private func logScreen(name: String, path: String) { + guard isEnabled else { return } + managers.forEach { manager in + manager.logScreen(name: name, path: path) + } + } + + private func logEvent(name: String) { + guard isEnabled else { return } + managers.forEach { manager in + manager.logEvent(name: name) + } + } + + // MARK: - section_one + + func logScreenS1DefOne() { + logScreen(name: "s1 def one", path: "s1_def_one/") + } + + func logEventS1DefTwo() { + logEvent(name: "s1 def two") + } + + // MARK: - section_two + + func logScreenS2DefOne() { + logScreen(name: "s2 def one", path: "s2_def_one/") + } + } + + """ + + if extensionContent != expect { + print(prettyFirstDifferenceBetweenStrings(s1: extensionContent, s2: expect)) + } + XCTAssertEqual(extensionContent.adaptForXCTest(), expect.adaptForXCTest()) + } +}