import Testing @testable import WmapParser @Test func shouldParseMultipleEntities() { let source = """ Water (0.9, 0.5) Bucket (0.8, 0.4) [x] Water -> Bucket """ let result = WmapParser.parse(source) #expect(result.components.count == 2) #expect( result.components.first == WmapParser.Component( label: "Water", coordinates: WmapParser.MapPoint(xCoordinate: 0.9, yCoordinate: 0.5), shape: .circle) ) #expect( result.components[1] == WmapParser.Component( label: "Bucket", coordinates: WmapParser.MapPoint(xCoordinate: 0.8, yCoordinate: 0.4), shape: .xMark) ) #expect(result.dependencies.count == 1) #expect( result.dependencies.first == WmapParser.Dependency(fromComponent: "Water", toComponent: "Bucket", isDirected: true) ) } @Test func shouldHandleUnixLineEndings() { let source = "Penguins (0.9, 0.5)\nI Use Arch BTW (0.8, 0.4) [x]" let result = WmapParser.parse(source) #expect(result.components.count == 2) #expect( result.components.first == WmapParser.Component( label: "Penguins", coordinates: WmapParser.MapPoint(xCoordinate: 0.9, yCoordinate: 0.5), shape: .circle ) ) #expect( result.components[1] == WmapParser.Component( label: "I Use Arch BTW", coordinates: WmapParser.MapPoint(xCoordinate: 0.8, yCoordinate: 0.4), shape: .xMark) ) } @Test func shouldHandleWindowsLineEndings() { let source = "Clippy (0.9, 0.5)\r\nSpace Cadet (0.8, 0.4) [x]" let result = WmapParser.parse(source) #expect(result.components.count == 2) #expect( result.components.first == WmapParser.Component( label: "Clippy", coordinates: WmapParser.MapPoint(xCoordinate: 0.9, yCoordinate: 0.5), shape: .circle) ) #expect( result.components[1] == WmapParser.Component( label: "Space Cadet", coordinates: WmapParser.MapPoint(xCoordinate: 0.8, yCoordinate: 0.4), shape: .xMark) ) } @Test func shouldHandleMacLineEndings() { let source = "SE/30 (0.9, 0.5)\rPerforma (0.8, 0.4) [x]" let result = WmapParser.parse(source) #expect(result.components.count == 2) #expect( result.components.first == WmapParser.Component( label: "SE/30", coordinates: WmapParser.MapPoint(xCoordinate: 0.9, yCoordinate: 0.5), shape: .circle) ) #expect( result.components[1] == WmapParser.Component( label: "Performa", coordinates: WmapParser.MapPoint(xCoordinate: 0.8, yCoordinate: 0.4), shape: .xMark) ) } @Test func shouldIgnoreEmptyLines() { let source = """ The Void (0.9, 0.5) The Abyss (0.8, 0.4) """ let result = WmapParser.parse(source) #expect(result.components.count == 2) #expect( result.components.first == WmapParser.Component( label: "The Void", coordinates: WmapParser.MapPoint(xCoordinate: 0.9, yCoordinate: 0.5), shape: .circle ) ) #expect( result.components[1] == WmapParser.Component( label: "The Abyss", coordinates: WmapParser.MapPoint(xCoordinate: 0.8, yCoordinate: 0.4), shape: .circle) ) } @Test func shouldHandleIncompleteNotes() { let source = "[Note]" let result = WmapParser.parse(source) #expect(result.components.count == 0) } @Test func shouldHandleIncompleteGroups() { let source = "[Group]" let result = WmapParser.parse(source) #expect(result.components.count == 0) } @Test func shouldHandleIncompleteNodesWithNoCoordinates() { let source = "I am a node? (" let result = WmapParser.parse(source) #expect(result.components.count == 0) } @Test func shouldHandleIncompleteNodesWithIncompleteCoordinates() { let source = "I am a node? (12" let result = WmapParser.parse(source) #expect(result.components.count == 0) } @Test func shouldHandleIncompleteNodesWithMissingYCoordinates() { let source = "I am a node? (12," let result = WmapParser.parse(source) #expect(result.components.count == 0) } @Test func shouldHandleIncompleteNodesWithUnclosedCoordinates() { let source = "I am a node? (12,21" let result = WmapParser.parse(source) #expect(result.components.count == 0) } @Test func shouldHandleIncompleteEvolutionWithoutValue() { let source = "[Evolution] I accidentally a +" let result = WmapParser.parse(source) #expect(result.components.count == 0) } @Test func shouldHandleIncompleteEvolutionWithoutComponent() { let source = "[Evolution]+" let result = WmapParser.parse(source) #expect(result.components.count == 0) } @Test func shouldHandleJustAParenthesis() { let source = " (" let result = WmapParser.parse(source) #expect(result.components.count == 0) } @Test func shouldIgnoreInvalidLines() { let source = """ Hello (0.9, 0.5) Oh No It's OK (0.8, 0.4) [ijole] NO IT ISN'T A-- B-> ( Hello -> It's OK [ """ let result = WmapParser.parse(source) #expect(result.components.count == 2) #expect( result.components.first == WmapParser.Component( label: "Hello", coordinates: WmapParser.MapPoint(xCoordinate: 0.9, yCoordinate: 0.5), shape: .circle) ) #expect( result.components[1] == WmapParser.Component( label: "It's OK", coordinates: WmapParser.MapPoint(xCoordinate: 0.8, yCoordinate: 0.4), shape: .circle) ) #expect(result.dependencies.count == 1) #expect( result.dependencies.first == WmapParser.Dependency(fromComponent: "Hello", toComponent: "It's OK", isDirected: true) ) } // Edge Cases @Test func shouldHandleEmptyInput() { let source = "" let result = WmapParser.parse(source) #expect(result.components.count == 0) } @Test func shouldHandleOnlyWhitespace() { let source = " \n \n " let result = WmapParser.parse(source) #expect(result.components.count == 0) } @Test func onlyLineBreaks() { let source = "\n" let result = WmapParser.parse(source) #expect(result.components.count == 0) } @Test func shouldHandleOnlyInvalidLines() { let source = "invalid\nstill invalid" let result = WmapParser.parse(source) #expect(result.components.count == 0) } @Test func shouldHandleComplexComponentLabels() { let source = "My Sü'per Complex Label 123 (0.5, 0.5)" let result = WmapParser.parse(source) #expect(result.components.count == 1) #expect( result.components.first == WmapParser.Component( label: "My Sü'per Complex Label 123", coordinates: WmapParser.MapPoint(xCoordinate: 0.5, yCoordinate: 0.5), shape: .circle) ) } // Comprehensive Example // swiftlint:disable:next function_body_length @Test func shouldParseACompleteWardleyMap() { let source = """ [I] 0.25 [II] 0.5 [III] 0.75 [IV] 1.0 Tea (0.9, 0.5) [Circle] Cup (0.8, 0.4) Kettle (0.7, 0.3) [Square] Hot Water (0.6, 0.2) Tea -> Cup Cup -> Kettle Kettle -> Hot Water [Note] (0.5, 0.5) This is our tea supply chain [Group] Tea, Cup, Kettle [Inertia] Kettle [Evolution] Tea + 0.1 """ let result = WmapParser.parse(source) // 4 stages + 4 components + 3 dependencies + 1 note + 1 group + 1 inertia + 1 evolution #expect(result.stages.count == 4) #expect(result.components.count == 4) #expect(result.dependencies.count == 3) #expect(result.notes.count == 1) #expect(result.groups.count == 1) #expect(result.inertias.count == 1) #expect(result.evolutions.count == 1) #expect(result.stages.first == WmapParser.Stage(stage: .stageI, value: 0.25)) #expect(result.stages[1] == WmapParser.Stage(stage: .stageII, value: 0.5)) #expect(result.stages[2] == WmapParser.Stage(stage: .stageIII, value: 0.75)) #expect(result.stages[3] == WmapParser.Stage(stage: .stageIV, value: 1.0)) #expect( result.components.first == WmapParser.Component( label: "Tea", coordinates: WmapParser.MapPoint(xCoordinate: 0.9, yCoordinate: 0.5), shape: .circle) ) #expect( result.components[1] == WmapParser.Component( label: "Cup", coordinates: WmapParser.MapPoint(xCoordinate: 0.8, yCoordinate: 0.4), shape: .circle) ) #expect( result.components[2] == WmapParser.Component( label: "Kettle", coordinates: WmapParser.MapPoint(xCoordinate: 0.7, yCoordinate: 0.3), shape: .square) ) #expect( result.components[3] == WmapParser.Component( label: "Hot Water", coordinates: WmapParser.MapPoint(xCoordinate: 0.6, yCoordinate: 0.2), shape: .circle) ) #expect( result.dependencies.first == WmapParser.Dependency(fromComponent: "Tea", toComponent: "Cup", isDirected: true) ) #expect( result.dependencies[1] == WmapParser.Dependency(fromComponent: "Cup", toComponent: "Kettle", isDirected: true) ) #expect( result.dependencies[2] == WmapParser.Dependency(fromComponent: "Kettle", toComponent: "Hot Water", isDirected: true) ) #expect( result.notes.first == WmapParser.Note( text: "This is our tea supply chain", coordinates: WmapParser.MapPoint(xCoordinate: 0.5, yCoordinate: 0.5)) ) #expect(result.groups.first?.components == ["Tea", "Cup", "Kettle"]) #expect(result.inertias.first?.component == "Kettle") #expect(result.evolutions.first == WmapParser.Evolution(component: "Tea", value: 0.1)) }