TextBasedRendererTests.swift 24 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016
  1. /*
  2. * Copyright 2023, gRPC Authors All rights reserved.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. //===----------------------------------------------------------------------===//
  17. //
  18. // This source file is part of the SwiftOpenAPIGenerator open source project
  19. //
  20. // Copyright (c) 2023 Apple Inc. and the SwiftOpenAPIGenerator project authors
  21. // Licensed under Apache License v2.0
  22. //
  23. // See LICENSE.txt for license information
  24. // See CONTRIBUTORS.txt for the list of SwiftOpenAPIGenerator project authors
  25. //
  26. // SPDX-License-Identifier: Apache-2.0
  27. //
  28. //===----------------------------------------------------------------------===//
  29. import XCTest
  30. @testable import GRPCCodeGen
  31. final class Test_TextBasedRenderer: XCTestCase {
  32. func testComment() throws {
  33. try _test(
  34. .inline(
  35. #"""
  36. Generated by foo
  37. Also, bar
  38. """#
  39. ),
  40. renderedBy: { $0.renderComment(_:) },
  41. rendersAs: #"""
  42. // Generated by foo
  43. //
  44. // Also, bar
  45. """#
  46. )
  47. try _test(
  48. .doc(
  49. #"""
  50. Generated by foo
  51. Also, bar
  52. """#
  53. ),
  54. renderedBy: { $0.renderComment(_:) },
  55. rendersAs: #"""
  56. /// Generated by foo
  57. ///
  58. /// Also, bar
  59. """#
  60. )
  61. try _test(
  62. .mark("Lorem ipsum", sectionBreak: false),
  63. renderedBy: { $0.renderComment(_:) },
  64. rendersAs: #"""
  65. // MARK: Lorem ipsum
  66. """#
  67. )
  68. try _test(
  69. .mark("Lorem ipsum", sectionBreak: true),
  70. renderedBy: { $0.renderComment(_:) },
  71. rendersAs: #"""
  72. // MARK: - Lorem ipsum
  73. """#
  74. )
  75. try _test(
  76. .inline(
  77. """
  78. Generated by foo\r\nAlso, bar
  79. """
  80. ),
  81. renderedBy: { $0.renderComment(_:) },
  82. rendersAs: #"""
  83. // Generated by foo
  84. // Also, bar
  85. """#
  86. )
  87. try _test(
  88. .preFormatted("/// Lorem ipsum\n"),
  89. renderedBy: { $0.renderComment(_:) },
  90. rendersAs: """
  91. /// Lorem ipsum
  92. """
  93. )
  94. try _test(
  95. .preFormatted("/// Lorem ipsum\n\n/// Lorem ipsum\n"),
  96. renderedBy: { $0.renderComment(_:) },
  97. rendersAs: """
  98. /// Lorem ipsum
  99. /// Lorem ipsum
  100. """
  101. )
  102. }
  103. func testImports() throws {
  104. try _test(nil, renderedBy: { $0.renderImports(_:) }, rendersAs: "")
  105. try _test(
  106. [
  107. ImportDescription(moduleName: "Foo"),
  108. ImportDescription(moduleName: "Bar"),
  109. ImportDescription(accessLevel: .fileprivate, moduleName: "BazFileprivate"),
  110. ImportDescription(accessLevel: .private, moduleName: "BazPrivate"),
  111. ImportDescription(accessLevel: .internal, moduleName: "BazInternal"),
  112. ImportDescription(accessLevel: .package, moduleName: "BazPackage"),
  113. ImportDescription(accessLevel: .public, moduleName: "BazPublic"),
  114. ],
  115. renderedBy: { $0.renderImports(_:) },
  116. rendersAs: #"""
  117. import Foo
  118. import Bar
  119. fileprivate import BazFileprivate
  120. private import BazPrivate
  121. internal import BazInternal
  122. package import BazPackage
  123. public import BazPublic
  124. """#
  125. )
  126. try _test(
  127. [ImportDescription(moduleName: "Foo", spi: "Secret")],
  128. renderedBy: { $0.renderImports(_:) },
  129. rendersAs: #"""
  130. @_spi(Secret) import Foo
  131. """#
  132. )
  133. try _test(
  134. [
  135. ImportDescription(
  136. moduleName: "Foo",
  137. preconcurrency: .onOS(["Bar", "Baz"])
  138. )
  139. ],
  140. renderedBy: { $0.renderImports(_:) },
  141. rendersAs: #"""
  142. #if os(Bar) || os(Baz)
  143. @preconcurrency import Foo
  144. #else
  145. import Foo
  146. #endif
  147. """#
  148. )
  149. try _test(
  150. [
  151. ImportDescription(moduleName: "Foo", preconcurrency: .always),
  152. ImportDescription(
  153. moduleName: "Bar",
  154. spi: "Secret",
  155. preconcurrency: .always
  156. ),
  157. ],
  158. renderedBy: { $0.renderImports(_:) },
  159. rendersAs: #"""
  160. @preconcurrency import Foo
  161. @preconcurrency @_spi(Secret) import Bar
  162. """#
  163. )
  164. try _test(
  165. [
  166. ImportDescription(
  167. moduleName: "Foo",
  168. item: ImportDescription.Item(kind: .typealias, name: "Bar")
  169. ),
  170. ImportDescription(
  171. moduleName: "Foo",
  172. item: ImportDescription.Item(kind: .struct, name: "Baz")
  173. ),
  174. ImportDescription(
  175. moduleName: "Foo",
  176. item: ImportDescription.Item(kind: .class, name: "Bac")
  177. ),
  178. ImportDescription(
  179. moduleName: "Foo",
  180. item: ImportDescription.Item(kind: .enum, name: "Bap")
  181. ),
  182. ImportDescription(
  183. moduleName: "Foo",
  184. item: ImportDescription.Item(kind: .protocol, name: "Bat")
  185. ),
  186. ImportDescription(
  187. moduleName: "Foo",
  188. item: ImportDescription.Item(kind: .let, name: "Bam")
  189. ),
  190. ImportDescription(
  191. moduleName: "Foo",
  192. item: ImportDescription.Item(kind: .var, name: "Bag")
  193. ),
  194. ImportDescription(
  195. moduleName: "Foo",
  196. item: ImportDescription.Item(kind: .func, name: "Bak")
  197. ),
  198. ImportDescription(
  199. moduleName: "Foo",
  200. spi: "Secret",
  201. item: ImportDescription.Item(kind: .func, name: "SecretBar")
  202. ),
  203. ImportDescription(
  204. moduleName: "Foo",
  205. preconcurrency: .always,
  206. item: ImportDescription.Item(kind: .func, name: "PreconcurrencyBar")
  207. ),
  208. ],
  209. renderedBy: { $0.renderImports(_:) },
  210. rendersAs: #"""
  211. import typealias Foo.Bar
  212. import struct Foo.Baz
  213. import class Foo.Bac
  214. import enum Foo.Bap
  215. import protocol Foo.Bat
  216. import let Foo.Bam
  217. import var Foo.Bag
  218. import func Foo.Bak
  219. @_spi(Secret) import func Foo.SecretBar
  220. @preconcurrency import func Foo.PreconcurrencyBar
  221. """#
  222. )
  223. }
  224. func testAccessModifiers() throws {
  225. try _test(
  226. .public,
  227. renderedBy: { $0.renderedAccessModifier(_:) },
  228. rendersAs: #"""
  229. public
  230. """#
  231. )
  232. try _test(
  233. .internal,
  234. renderedBy: { $0.renderedAccessModifier(_:) },
  235. rendersAs: #"""
  236. internal
  237. """#
  238. )
  239. try _test(
  240. .fileprivate,
  241. renderedBy: { $0.renderedAccessModifier(_:) },
  242. rendersAs: #"""
  243. fileprivate
  244. """#
  245. )
  246. try _test(
  247. .private,
  248. renderedBy: { $0.renderedAccessModifier(_:) },
  249. rendersAs: #"""
  250. private
  251. """#
  252. )
  253. }
  254. func testLiterals() throws {
  255. try _test(
  256. .string("hi"),
  257. renderedBy: { $0.renderLiteral(_:) },
  258. rendersAs: #"""
  259. "hi"
  260. """#
  261. )
  262. try _test(
  263. .string("this string: \"foo\""),
  264. renderedBy: { $0.renderLiteral(_:) },
  265. rendersAs: #"""
  266. #"this string: "foo""#
  267. """#
  268. )
  269. try _test(
  270. .nil,
  271. renderedBy: { $0.renderLiteral(_:) },
  272. rendersAs: #"""
  273. nil
  274. """#
  275. )
  276. try _test(
  277. .array([]),
  278. renderedBy: { $0.renderLiteral(_:) },
  279. rendersAs: #"""
  280. []
  281. """#
  282. )
  283. try _test(
  284. .array([.literal(.nil)]),
  285. renderedBy: { $0.renderLiteral(_:) },
  286. rendersAs: #"""
  287. [
  288. nil
  289. ]
  290. """#
  291. )
  292. try _test(
  293. .array([.literal(.nil), .literal(.nil)]),
  294. renderedBy: { $0.renderLiteral(_:) },
  295. rendersAs: #"""
  296. [
  297. nil,
  298. nil
  299. ]
  300. """#
  301. )
  302. try _test(
  303. .dictionary([]),
  304. renderedBy: { $0.renderLiteral(_:) },
  305. rendersAs: #"""
  306. [:]
  307. """#
  308. )
  309. try _test(
  310. .dictionary([.init(key: .literal("foo"), value: .literal("bar"))]),
  311. renderedBy: { $0.renderLiteral(_:) },
  312. rendersAs: #"""
  313. [
  314. "foo": "bar"
  315. ]
  316. """#
  317. )
  318. try _test(
  319. .dictionary([
  320. .init(key: .literal("foo"), value: .literal("bar")),
  321. .init(key: .literal("bar"), value: .literal("baz")),
  322. ]),
  323. renderedBy: { $0.renderLiteral(_:) },
  324. rendersAs: #"""
  325. [
  326. "foo": "bar",
  327. "bar": "baz"
  328. ]
  329. """#
  330. )
  331. }
  332. func testExpression() throws {
  333. try _test(
  334. .literal(.nil),
  335. renderedBy: { $0.renderExpression(_:) },
  336. rendersAs: #"""
  337. nil
  338. """#
  339. )
  340. try _test(
  341. .identifierPattern("foo"),
  342. renderedBy: { $0.renderExpression(_:) },
  343. rendersAs: #"""
  344. foo
  345. """#
  346. )
  347. try _test(
  348. .memberAccess(.init(left: .identifierPattern("foo"), right: "bar")),
  349. renderedBy: { $0.renderExpression(_:) },
  350. rendersAs: #"""
  351. foo.bar
  352. """#
  353. )
  354. try _test(
  355. .functionCall(
  356. .init(
  357. calledExpression: .identifierPattern("callee"),
  358. arguments: [.init(label: nil, expression: .identifierPattern("foo"))]
  359. )
  360. ),
  361. renderedBy: { $0.renderExpression(_:) },
  362. rendersAs: #"""
  363. callee(foo)
  364. """#
  365. )
  366. }
  367. func testDeclaration() throws {
  368. try _test(
  369. .variable(kind: .let, left: "foo"),
  370. renderedBy: { $0.renderDeclaration(_:) },
  371. rendersAs: #"""
  372. let foo
  373. """#
  374. )
  375. try _test(
  376. .extension(.init(onType: "String", declarations: [])),
  377. renderedBy: { $0.renderDeclaration(_:) },
  378. rendersAs: #"""
  379. extension String {
  380. }
  381. """#
  382. )
  383. try _test(
  384. .struct(.init(name: "Foo")),
  385. renderedBy: { $0.renderDeclaration(_:) },
  386. rendersAs: #"""
  387. struct Foo {}
  388. """#
  389. )
  390. try _test(
  391. .protocol(.init(name: "Foo")),
  392. renderedBy: { $0.renderDeclaration(_:) },
  393. rendersAs: #"""
  394. protocol Foo {}
  395. """#
  396. )
  397. try _test(
  398. .enum(.init(name: "Foo")),
  399. renderedBy: { $0.renderDeclaration(_:) },
  400. rendersAs: #"""
  401. enum Foo {}
  402. """#
  403. )
  404. try _test(
  405. .typealias(.init(name: "foo", existingType: .member(["Foo", "Bar"]))),
  406. renderedBy: { $0.renderDeclaration(_:) },
  407. rendersAs: #"""
  408. typealias foo = Foo.Bar
  409. """#
  410. )
  411. try _test(
  412. .function(FunctionDescription.init(kind: .function(name: "foo"), body: [])),
  413. renderedBy: { $0.renderDeclaration(_:) },
  414. rendersAs: #"""
  415. func foo() {}
  416. """#
  417. )
  418. }
  419. func testFunctionKind() throws {
  420. try _test(
  421. .initializer,
  422. renderedBy: { $0.renderedFunctionKind(_:) },
  423. rendersAs: #"""
  424. init
  425. """#
  426. )
  427. try _test(
  428. .function(name: "funky"),
  429. renderedBy: { $0.renderedFunctionKind(_:) },
  430. rendersAs: #"""
  431. func funky
  432. """#
  433. )
  434. try _test(
  435. .function(name: "funky", isStatic: true),
  436. renderedBy: { $0.renderedFunctionKind(_:) },
  437. rendersAs: #"""
  438. static func funky
  439. """#
  440. )
  441. }
  442. func testFunctionKeyword() throws {
  443. try _test(
  444. .throws,
  445. renderedBy: { $0.renderedFunctionKeyword(_:) },
  446. rendersAs: #"""
  447. throws
  448. """#
  449. )
  450. try _test(
  451. .async,
  452. renderedBy: { $0.renderedFunctionKeyword(_:) },
  453. rendersAs: #"""
  454. async
  455. """#
  456. )
  457. }
  458. func testParameter() throws {
  459. try _test(
  460. .init(label: "l", name: "n", type: .member("T"), defaultValue: .literal(.nil)),
  461. renderedBy: { $0.renderParameter(_:) },
  462. rendersAs: #"""
  463. l n: T = nil
  464. """#
  465. )
  466. try _test(
  467. .init(label: nil, name: "n", type: .member("T"), defaultValue: .literal(.nil)),
  468. renderedBy: { $0.renderParameter(_:) },
  469. rendersAs: #"""
  470. _ n: T = nil
  471. """#
  472. )
  473. try _test(
  474. .init(label: "l", name: nil, type: .member("T"), defaultValue: .literal(.nil)),
  475. renderedBy: { $0.renderParameter(_:) },
  476. rendersAs: #"""
  477. l: T = nil
  478. """#
  479. )
  480. try _test(
  481. .init(label: nil, name: nil, type: .member("T"), defaultValue: .literal(.nil)),
  482. renderedBy: { $0.renderParameter(_:) },
  483. rendersAs: #"""
  484. _: T = nil
  485. """#
  486. )
  487. try _test(
  488. .init(label: nil, name: nil, type: .member("T"), defaultValue: nil),
  489. renderedBy: { $0.renderParameter(_:) },
  490. rendersAs: #"""
  491. _: T
  492. """#
  493. )
  494. }
  495. func testGenericFunction() throws {
  496. try _test(
  497. .init(
  498. accessModifier: .public,
  499. kind: .function(name: "f"),
  500. generics: [.member("R")],
  501. parameters: [],
  502. whereClause: WhereClause(requirements: [.conformance("R", "Sendable")]),
  503. body: []
  504. ),
  505. renderedBy: { $0.renderFunction(_:) },
  506. rendersAs: #"""
  507. public func f<R>() where R: Sendable {}
  508. """#
  509. )
  510. try _test(
  511. .init(
  512. accessModifier: .public,
  513. kind: .function(name: "f"),
  514. generics: [.member("R"), .member("T")],
  515. parameters: [],
  516. whereClause: WhereClause(requirements: [
  517. .conformance("R", "Sendable"), .conformance("T", "Encodable"),
  518. ]),
  519. body: []
  520. ),
  521. renderedBy: { $0.renderFunction(_:) },
  522. rendersAs: #"""
  523. public func f<R, T>() where R: Sendable, T: Encodable {}
  524. """#
  525. )
  526. }
  527. func testFunction() throws {
  528. try _test(
  529. .init(accessModifier: .public, kind: .function(name: "f"), parameters: [], body: []),
  530. renderedBy: { $0.renderFunction(_:) },
  531. rendersAs: #"""
  532. public func f() {}
  533. """#
  534. )
  535. try _test(
  536. .init(
  537. accessModifier: .public,
  538. kind: .function(name: "f"),
  539. parameters: [.init(label: "a", name: "b", type: .member("C"), defaultValue: nil)],
  540. body: []
  541. ),
  542. renderedBy: { $0.renderFunction(_:) },
  543. rendersAs: #"""
  544. public func f(a b: C) {}
  545. """#
  546. )
  547. try _test(
  548. .init(
  549. accessModifier: .public,
  550. kind: .function(name: "f"),
  551. parameters: [
  552. .init(label: "a", name: "b", type: .member("C"), defaultValue: nil),
  553. .init(label: nil, name: "d", type: .member("E"), defaultValue: .literal(.string("f"))),
  554. ],
  555. body: []
  556. ),
  557. renderedBy: { $0.renderFunction(_:) },
  558. rendersAs: #"""
  559. public func f(
  560. a b: C,
  561. _ d: E = "f"
  562. ) {}
  563. """#
  564. )
  565. try _test(
  566. .init(
  567. kind: .function(name: "f"),
  568. parameters: [],
  569. keywords: [.async, .throws],
  570. returnType: .identifierType(TypeName.string)
  571. ),
  572. renderedBy: { $0.renderFunction(_:) },
  573. rendersAs: #"""
  574. func f() async throws -> Swift.String
  575. """#
  576. )
  577. }
  578. func testIdentifiers() throws {
  579. try _test(
  580. .pattern("foo"),
  581. renderedBy: { $0.renderIdentifier(_:) },
  582. rendersAs: #"""
  583. foo
  584. """#
  585. )
  586. }
  587. func testMemberAccess() throws {
  588. try _test(
  589. .init(left: .identifierPattern("foo"), right: "bar"),
  590. renderedBy: { $0.renderMemberAccess(_:) },
  591. rendersAs: #"""
  592. foo.bar
  593. """#
  594. )
  595. try _test(
  596. .init(left: nil, right: "bar"),
  597. renderedBy: { $0.renderMemberAccess(_:) },
  598. rendersAs: #"""
  599. .bar
  600. """#
  601. )
  602. }
  603. func testFunctionCallArgument() throws {
  604. try _test(
  605. .init(label: "foo", expression: .identifierPattern("bar")),
  606. renderedBy: { $0.renderFunctionCallArgument(_:) },
  607. rendersAs: #"""
  608. foo: bar
  609. """#
  610. )
  611. try _test(
  612. .init(label: nil, expression: .identifierPattern("bar")),
  613. renderedBy: { $0.renderFunctionCallArgument(_:) },
  614. rendersAs: #"""
  615. bar
  616. """#
  617. )
  618. }
  619. func testFunctionCall() throws {
  620. try _test(
  621. .functionCall(.init(calledExpression: .identifierPattern("callee"))),
  622. renderedBy: { $0.renderExpression(_:) },
  623. rendersAs: #"""
  624. callee()
  625. """#
  626. )
  627. try _test(
  628. .functionCall(
  629. .init(
  630. calledExpression: .identifierPattern("callee"),
  631. arguments: [.init(label: "foo", expression: .identifierPattern("bar"))]
  632. )
  633. ),
  634. renderedBy: { $0.renderExpression(_:) },
  635. rendersAs: #"""
  636. callee(foo: bar)
  637. """#
  638. )
  639. try _test(
  640. .functionCall(
  641. .init(
  642. calledExpression: .identifierPattern("callee"),
  643. arguments: [
  644. .init(label: "foo", expression: .identifierPattern("bar")),
  645. .init(label: "baz", expression: .identifierPattern("boo")),
  646. ]
  647. )
  648. ),
  649. renderedBy: { $0.renderExpression(_:) },
  650. rendersAs: #"""
  651. callee(
  652. foo: bar,
  653. baz: boo
  654. )
  655. """#
  656. )
  657. }
  658. func testExtension() throws {
  659. try _test(
  660. .init(
  661. accessModifier: .public,
  662. onType: "Info",
  663. declarations: [.variable(kind: .let, left: "foo", type: .member("Int"))]
  664. ),
  665. renderedBy: { $0.renderExtension(_:) },
  666. rendersAs: #"""
  667. public extension Info {
  668. let foo: Int
  669. }
  670. """#
  671. )
  672. }
  673. func testDeprecation() throws {
  674. try _test(
  675. .init(),
  676. renderedBy: { $0.renderDeprecation(_:) },
  677. rendersAs: #"""
  678. @available(*, deprecated)
  679. """#
  680. )
  681. try _test(
  682. .init(message: "some message"),
  683. renderedBy: { $0.renderDeprecation(_:) },
  684. rendersAs: #"""
  685. @available(*, deprecated, message: "some message")
  686. """#
  687. )
  688. try _test(
  689. .init(renamed: "newSymbol(param:)"),
  690. renderedBy: { $0.renderDeprecation(_:) },
  691. rendersAs: #"""
  692. @available(*, deprecated, renamed: "newSymbol(param:)")
  693. """#
  694. )
  695. try _test(
  696. .init(message: "some message", renamed: "newSymbol(param:)"),
  697. renderedBy: { $0.renderDeprecation(_:) },
  698. rendersAs: #"""
  699. @available(*, deprecated, message: "some message", renamed: "newSymbol(param:)")
  700. """#
  701. )
  702. }
  703. func testAvailability() throws {
  704. try _test(
  705. .init(osVersions: [
  706. .init(os: .macOS, version: "12.0"),
  707. .init(os: .iOS, version: "13.1.2"),
  708. .init(os: .watchOS, version: "8.1.2"),
  709. .init(os: .tvOS, version: "15.0.2"),
  710. ]),
  711. renderedBy: { $0.renderAvailability(_:) },
  712. rendersAs: #"""
  713. @available(macOS 12.0, iOS 13.1.2, watchOS 8.1.2, tvOS 15.0.2, *)
  714. """#
  715. )
  716. }
  717. func testBindingKind() throws {
  718. try _test(
  719. .var,
  720. renderedBy: { $0.renderedBindingKind(_:) },
  721. rendersAs: #"""
  722. var
  723. """#
  724. )
  725. try _test(
  726. .let,
  727. renderedBy: { $0.renderedBindingKind(_:) },
  728. rendersAs: #"""
  729. let
  730. """#
  731. )
  732. }
  733. func testVariable() throws {
  734. try _test(
  735. .init(
  736. accessModifier: .public,
  737. isStatic: true,
  738. kind: .let,
  739. left: .identifierPattern("foo"),
  740. type: .init(TypeName.string),
  741. right: .literal(.string("bar"))
  742. ),
  743. renderedBy: { $0.renderVariable(_:) },
  744. rendersAs: #"""
  745. public static let foo: Swift.String = "bar"
  746. """#
  747. )
  748. try _test(
  749. .init(
  750. accessModifier: .internal,
  751. isStatic: false,
  752. kind: .var,
  753. left: .identifierPattern("foo"),
  754. type: nil,
  755. right: nil
  756. ),
  757. renderedBy: { $0.renderVariable(_:) },
  758. rendersAs: #"""
  759. internal var foo
  760. """#
  761. )
  762. try _test(
  763. .init(
  764. kind: .var,
  765. left: .identifierPattern("foo"),
  766. type: .init(TypeName.int),
  767. getter: [CodeBlock.expression(.literal(.int(42)))]
  768. ),
  769. renderedBy: { $0.renderVariable(_:) },
  770. rendersAs: #"""
  771. var foo: Swift.Int {
  772. 42
  773. }
  774. """#
  775. )
  776. try _test(
  777. .init(
  778. kind: .var,
  779. left: .identifierPattern("foo"),
  780. type: .init(TypeName.int),
  781. getter: [CodeBlock.expression(.literal(.int(42)))],
  782. getterEffects: [.throws]
  783. ),
  784. renderedBy: { $0.renderVariable(_:) },
  785. rendersAs: #"""
  786. var foo: Swift.Int {
  787. get throws {
  788. 42
  789. }
  790. }
  791. """#
  792. )
  793. }
  794. func testStruct() throws {
  795. try _test(
  796. .init(name: "Structy"),
  797. renderedBy: { $0.renderStruct(_:) },
  798. rendersAs: #"""
  799. struct Structy {}
  800. """#
  801. )
  802. }
  803. func testProtocol() throws {
  804. try _test(
  805. .init(name: "Protocoly"),
  806. renderedBy: { $0.renderProtocol(_:) },
  807. rendersAs: #"""
  808. protocol Protocoly {}
  809. """#
  810. )
  811. }
  812. func testEnum() throws {
  813. try _test(
  814. .init(name: "Enumy"),
  815. renderedBy: { $0.renderEnum(_:) },
  816. rendersAs: #"""
  817. enum Enumy {}
  818. """#
  819. )
  820. }
  821. func testCodeBlockItem() throws {
  822. try _test(
  823. .declaration(.variable(kind: .let, left: "foo")),
  824. renderedBy: { $0.renderCodeBlockItem(_:) },
  825. rendersAs: #"""
  826. let foo
  827. """#
  828. )
  829. try _test(
  830. .expression(.literal(.nil)),
  831. renderedBy: { $0.renderCodeBlockItem(_:) },
  832. rendersAs: #"""
  833. nil
  834. """#
  835. )
  836. }
  837. func testCodeBlock() throws {
  838. try _test(
  839. .init(
  840. comment: .inline("- MARK: Section"),
  841. item: .declaration(.variable(kind: .let, left: "foo"))
  842. ),
  843. renderedBy: { $0.renderCodeBlock(_:) },
  844. rendersAs: #"""
  845. // - MARK: Section
  846. let foo
  847. """#
  848. )
  849. try _test(
  850. .init(comment: nil, item: .declaration(.variable(kind: .let, left: "foo"))),
  851. renderedBy: { $0.renderCodeBlock(_:) },
  852. rendersAs: #"""
  853. let foo
  854. """#
  855. )
  856. }
  857. func testTypealias() throws {
  858. try _test(
  859. .init(name: "inty", existingType: .member("Int")),
  860. renderedBy: { $0.renderTypealias(_:) },
  861. rendersAs: #"""
  862. typealias inty = Int
  863. """#
  864. )
  865. try _test(
  866. .init(accessModifier: .private, name: "inty", existingType: .member("Int")),
  867. renderedBy: { $0.renderTypealias(_:) },
  868. rendersAs: #"""
  869. private typealias inty = Int
  870. """#
  871. )
  872. }
  873. func testFile() throws {
  874. try _test(
  875. .init(
  876. topComment: .inline("hi"),
  877. imports: [.init(moduleName: "Foo")],
  878. codeBlocks: [.init(comment: nil, item: .declaration(.struct(.init(name: "Bar"))))]
  879. ),
  880. renderedBy: { $0.renderFile(_:) },
  881. rendersAs: #"""
  882. // hi
  883. import Foo
  884. struct Bar {}
  885. """#
  886. )
  887. }
  888. func testIndentation() throws {
  889. try _test(
  890. .init(
  891. topComment: .inline("hi"),
  892. imports: [.init(moduleName: "Foo")],
  893. codeBlocks: [
  894. .init(
  895. comment: nil,
  896. item: .declaration(.struct(.init(name: "Bar", members: [.struct(.init(name: "Baz"))])))
  897. )
  898. ]
  899. ),
  900. renderedBy: { $0.renderFile(_:) },
  901. rendersAs: #"""
  902. // hi
  903. import Foo
  904. struct Bar {
  905. struct Baz {}
  906. }
  907. """#,
  908. indentation: 2
  909. )
  910. try _test(
  911. .array([.literal(.nil), .literal(.nil)]),
  912. renderedBy: { $0.renderLiteral(_:) },
  913. rendersAs: #"""
  914. [
  915. nil,
  916. nil
  917. ]
  918. """#,
  919. indentation: 3
  920. )
  921. try _test(
  922. .init(
  923. kind: .var,
  924. left: .identifierPattern("foo"),
  925. type: .init(TypeName.int),
  926. getter: [CodeBlock.expression(.literal(.int(42)))],
  927. getterEffects: [.throws]
  928. ),
  929. renderedBy: { $0.renderVariable(_:) },
  930. rendersAs: #"""
  931. var foo: Swift.Int {
  932. get throws {
  933. 42
  934. }
  935. }
  936. """#,
  937. indentation: 5
  938. )
  939. }
  940. }
  941. extension Test_TextBasedRenderer {
  942. func _test<Input>(
  943. _ input: Input,
  944. renderedBy renderClosure: (TextBasedRenderer) -> ((Input) -> String),
  945. rendersAs output: String,
  946. file: StaticString = #filePath,
  947. line: UInt = #line,
  948. indentation: Int = 4
  949. ) throws {
  950. let renderer = TextBasedRenderer(indentation: indentation)
  951. XCTAssertEqual(renderClosure(renderer)(input), output, file: file, line: line)
  952. }
  953. func _test<Input>(
  954. _ input: Input,
  955. renderedBy renderClosure: (TextBasedRenderer) -> ((Input) -> Void),
  956. rendersAs output: String,
  957. file: StaticString = #filePath,
  958. line: UInt = #line,
  959. indentation: Int = 4
  960. ) throws {
  961. try _test(
  962. input,
  963. renderedBy: { renderer in
  964. let closure = renderClosure(renderer)
  965. return { input in
  966. closure(input)
  967. return renderer.renderedContents()
  968. }
  969. },
  970. rendersAs: output,
  971. indentation: indentation
  972. )
  973. }
  974. }