Skip to content

Commit f4d4d68

Browse files
author
Adora Lynch
committed
Merge branch 'main' of github.com:jpsim/Yams
2 parents 293100b + cbc0217 commit f4d4d68

File tree

10 files changed

+125
-19
lines changed

10 files changed

+125
-19
lines changed

.github/workflows/swiftpm.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ jobs:
6969
name: macOS 15 with Xcode ${{ matrix.xcode_version }}
7070
strategy:
7171
matrix:
72-
xcode_version: ['15.4', '16.0', '16.2', '16.3']
72+
xcode_version: ['16.0', '16.2', '16.3']
7373
runs-on: macos-15
7474
env:
7575
DEVELOPER_DIR: /Applications/Xcode_${{ matrix.xcode_version }}.app
@@ -79,7 +79,7 @@ jobs:
7979
- run: YAMS_DEFAULT_ENCODING=UTF16 swift test --parallel
8080
- run: YAMS_DEFAULT_ENCODING=UTF8 swift test --parallel
8181
- name: Code Coverage
82-
if: matrix.xcode_version == '15.4'
82+
if: matrix.xcode_version == '16.0'
8383
run: |
8484
swift test --enable-code-coverage
8585
xcrun llvm-cov export -format="lcov" .build/debug/YamsPackageTests.xctest/Contents/MacOS/YamsPackageTests -instr-profile .build/debug/codecov/default.profdata > coverage.lcov

.github/workflows/xcodebuild.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ jobs:
9999
name: macOS 15 with Xcode ${{ matrix.xcode_version }}
100100
strategy:
101101
matrix:
102-
xcode_version: ['15.4', '16.0', '16.2', '16.3']
102+
xcode_version: ['16.0', '16.2', '16.3']
103103
xcode_flags: ['-scheme Yams -project Yams.xcodeproj']
104104
runs-on: macos-15
105105
env:

Sources/Yams/Decoder.swift

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,14 @@ extension _Decoder: SingleValueDecodingContainer {
340340
return dereferenced
341341
}
342342

343-
let constructed = try _construct(type)
343+
var constructed = try _construct(type)
344+
345+
if var anchorCoding = constructed as? YamlAnchorCoding,
346+
anchorCoding.yamlAnchor == nil,
347+
let anchor = self.node.anchor {
348+
anchorCoding.yamlAnchor = anchor
349+
constructed = anchorCoding as! T // swiftlint:disable:this force_cast
350+
}
344351

345352
recordAnchor(constructed)
346353

Sources/Yams/Encoder.swift

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,17 @@ extension _Encoder: SingleValueEncodingContainer {
243243
try encode(yamlEncodable: value)
244244
}
245245

246+
func encode<T>(_ value: T) throws where T: Encodable {
247+
assertCanEncodeNewValue()
248+
if let encodable = value as? YAMLEncodable {
249+
try encode(yamlEncodable: encodable)
250+
} else {
251+
try resolveAlias(for: value) {
252+
try value.encode(to: self)
253+
}
254+
}
255+
}
256+
246257
private func encode(yamlEncodable encodable: YAMLEncodable) throws {
247258
func encodeNode() {
248259
node = encodable.box()
@@ -264,7 +275,7 @@ extension _Encoder: SingleValueEncodingContainer {
264275
return // nothing left to do
265276
}
266277

267-
if let orphanedAnchor = self.node.anchor {
278+
if let orphanedAnchor = self.node.anchor, self.node.isScalar {
268279
// our sub-tree was a single value container which declared an anchor
269280
// that anchor will not be represented in the final tree
270281
// because `anchor` is the prevailing value in this context
@@ -293,17 +304,6 @@ extension _Encoder: SingleValueEncodingContainer {
293304
}
294305
}
295306

296-
func encode<T>(_ value: T) throws where T: Encodable {
297-
assertCanEncodeNewValue()
298-
if let encodable = value as? YAMLEncodable {
299-
try encode(yamlEncodable: encodable)
300-
} else {
301-
try resolveAlias(for: value) {
302-
try value.encode(to: self)
303-
}
304-
}
305-
}
306-
307307
// MARK: -
308308

309309
/// Asserts that a single value can be encoded at the current coding path

Sources/Yams/Node.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,13 @@ extension Node: ExpressibleByStringLiteral {
300300
extension Node {
301301
// MARK: Internal convenience accessors
302302

303+
var isScalar: Bool {
304+
if case .scalar = self {
305+
return true
306+
}
307+
return false
308+
}
309+
303310
var isMapping: Bool {
304311
if case .mapping = self {
305312
return true

Tests/LinuxMain.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ XCTMain([
77
testCase(EmitterTests.allTests),
88
testCase(EncoderTests.allTests),
99
testCase(MarkTests.allTests),
10+
testCase(NodeInternalHelpersTests.allTests),
1011
testCase(NodeTests.allTests),
1112
testCase(PerformanceTests.allTests),
1213
testCase(RepresenterTests.allTests),

Tests/YamsTests/AnchorCodingTests.swift

Lines changed: 60 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ class AnchorCodingTests: XCTestCase {
9696
}
9797
}
9898

99+
// swiftlint:disable:next type_body_length
99100
class AnchorAliasingTests: XCTestCase {
100101

101102
/// CYaml library does not detect identical values and automatically alias them.
@@ -225,7 +226,8 @@ class AnchorAliasingTests: XCTestCase {
225226
/// If types conform to YamlAnchorProviding and are NOT Hashable-Equal then
226227
/// HashableAliasingStrategy does not alias them even though their members may still be
227228
/// Hashable-Equal and therefor maybe aliased.
228-
/// Note particularly that the to Simple* values here have exactly the same encoded representation,
229+
/// Note particularly that the to SimpleSimpleWithoutAnchor* and the int-valued types here
230+
/// have exactly the same encoded representation,
229231
/// they're just different types and thus not Hashable-Equal
230232
func testEncoderAutoAlias_Hashable_NoAnchor() throws {
231233
let differentTypesNoAnchors = SimplePair(first:
@@ -359,6 +361,53 @@ class AnchorAliasingTests: XCTestCase {
359361
try _testMetaPropertyKeyExposure(source: string)
360362
}
361363

364+
/// Test that RawRepresentable types which conform toYamlAnchorCoding preserve their Anchors round-trip
365+
func testDecoder_anchorPreserving_RawRepresentable_mapping() throws {
366+
var intWithAnchor: SimpleIntRepresesnting = 52
367+
intWithAnchor.yamlAnchor = "fifty_two"
368+
let subject = ["key": intWithAnchor]
369+
370+
var options = YAMLEncoder.Options()
371+
options.redundancyAliasingStrategy = StrictEncodableAliasingStrategy()
372+
_testRoundTrip(of: subject,
373+
with: options,
374+
expectedYAML: """
375+
key: &fifty_two 52
376+
377+
""" )
378+
}
379+
380+
/// Test that RawRepresentable types which conform toYamlAnchorCoding preserve their Anchors round-trip
381+
func testDecoder_anchorPreserving_RawRepresentable_sequence() throws {
382+
var intWithAnchor: SimpleIntRepresesnting = 52
383+
intWithAnchor.yamlAnchor = "fifty_two"
384+
let subject = [intWithAnchor]
385+
386+
var options = YAMLEncoder.Options()
387+
options.redundancyAliasingStrategy = StrictEncodableAliasingStrategy()
388+
_testRoundTrip(of: subject,
389+
with: options,
390+
expectedYAML: """
391+
- &fifty_two 52
392+
393+
""" )
394+
}
395+
396+
/// Test that RawRepresentable types which conform toYamlAnchorCoding preserve their Anchors round-trip
397+
func testDecoder_anchorPreserving_RawRepresentable_scalar() throws {
398+
var intWithAnchor: SimpleIntRepresesnting = 52
399+
intWithAnchor.yamlAnchor = "fifty_two"
400+
401+
var options = YAMLEncoder.Options()
402+
options.redundancyAliasingStrategy = StrictEncodableAliasingStrategy()
403+
_testRoundTrip(of: intWithAnchor,
404+
with: options,
405+
expectedYAML: """
406+
&fifty_two 52
407+
408+
""" )
409+
}
410+
362411
private func _testMetaPropertyKeyExposure(source: String) throws {
363412
struct KeyCountAssertingStruct: Codable {
364413
var someInt: Int
@@ -445,7 +494,11 @@ extension Int {
445494
}
446495
}
447496

448-
private struct SimpleIntRepresesnting: RawRepresentable, Codable, Hashable, ExpressibleByIntegerLiteral {
497+
private struct SimpleIntRepresesnting: RawRepresentable,
498+
Codable,
499+
Hashable,
500+
ExpressibleByIntegerLiteral,
501+
YamlAnchorCoding {
449502
init(integerLiteral value: Int) {
450503
self.rawValue = value
451504
}
@@ -455,6 +508,11 @@ private struct SimpleIntRepresesnting: RawRepresentable, Codable, Hashable, Expr
455508
}
456509

457510
let rawValue: Int
511+
var yamlAnchor: Anchor?
512+
513+
static func == (lhs: Self, rhs: Self) -> Bool {
514+
lhs.rawValue == rhs.rawValue && lhs.yamlAnchor == rhs.yamlAnchor
515+
}
458516
}
459517

460518
// swiftlint:disable:this file_length

Tests/YamsTests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ add_library(YamsTests
77
EmitterTests.swift
88
EncoderTests.swift
99
MarkTests.swift
10+
NodeInternalHelpersTests.swift
1011
NodeTests.swift
1112
PerformanceTests.swift
1213
RepresenterTests.swift

Tests/YamsTests/EncoderTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -454,7 +454,7 @@ where T: Codable, T: Equatable {
454454
let producedYAML = try encoder.encode(value)
455455

456456
if let expectedYAML = yamlString {
457-
XCTAssertEqual(producedYAML, expectedYAML, "Produced YAML not identical to expected YAML.",
457+
XCTAssertEqual("\n"+producedYAML, "\n"+expectedYAML, "Produced YAML not identical to expected YAML.",
458458
file: (file), line: line)
459459
}
460460

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
//
2+
// NodeTests.swift
3+
// Yams
4+
//
5+
// Created by Adora Lynch on 6/23/25.
6+
// Copyright (c) 2024 Yams. All rights reserved.
7+
//
8+
9+
import Foundation
10+
import XCTest
11+
@testable import Yams
12+
13+
final class NodeInternalHelpersTests: XCTestCase, @unchecked Sendable {
14+
// swiftlint:disable force_try
15+
func testIsScalar() {
16+
var node = Node("1") // a scalar
17+
XCTAssertEqual(node.isScalar, true)
18+
node = try! Node(["key": "1"]) // a mapping
19+
XCTAssertEqual(node.isScalar, false)
20+
node = try! Node(["one", "1"]) // a sequnce
21+
XCTAssertEqual(node.isScalar, false)
22+
}
23+
// swiftlint:enable force_try
24+
}
25+
26+
extension NodeInternalHelpersTests {
27+
static var allTests: [(String, (NodeInternalHelpersTests) -> () throws -> Void)] {
28+
return [
29+
("testIsScalar", testIsScalar)
30+
]
31+
}
32+
}

0 commit comments

Comments
 (0)