15
15
*/
16
16
package com.diffplug.selfie
17
17
18
- import com.diffplug.selfie.guts.DiskSnapshotTodo
19
18
import com.diffplug.selfie.guts.DiskStorage
20
19
import com.diffplug.selfie.guts.LiteralBoolean
21
20
import com.diffplug.selfie.guts.LiteralFormat
@@ -24,16 +23,138 @@ import com.diffplug.selfie.guts.LiteralLong
24
23
import com.diffplug.selfie.guts.LiteralString
25
24
import com.diffplug.selfie.guts.LiteralValue
26
25
import com.diffplug.selfie.guts.SnapshotSystem
26
+ import com.diffplug.selfie.guts.TodoStub
27
27
import com.diffplug.selfie.guts.recordCall
28
28
import kotlin.io.encoding.Base64
29
29
import kotlin.io.encoding.ExperimentalEncodingApi
30
30
import kotlin.jvm.JvmOverloads
31
31
32
- open class LiteralStringSelfie
33
- internal constructor (
34
- protected val actual: Snapshot ,
32
+ /* * A selfie which can be stored into a selfie-managed file. */
33
+ open class DiskSelfie
34
+ internal constructor (protected val actual: Snapshot , protected val disk: DiskStorage ) :
35
+ FluentFacet {
36
+ @JvmOverloads
37
+ open fun toMatchDisk (sub : String = ""): DiskSelfie {
38
+ val call = recordCall(false )
39
+ if (Selfie .system.mode.canWrite(false , call, Selfie .system)) {
40
+ disk.writeDisk(actual, sub, call)
41
+ } else {
42
+ assertEqual(disk.readDisk(sub, call), actual, Selfie .system)
43
+ }
44
+ return this
45
+ }
46
+
47
+ @JvmOverloads
48
+ open fun toMatchDisk_TODO (sub : String = ""): DiskSelfie {
49
+ val call = recordCall(false )
50
+ if (Selfie .system.mode.canWrite(true , call, Selfie .system)) {
51
+ disk.writeDisk(actual, sub, call)
52
+ Selfie .system.writeInline(TodoStub .toMatchDisk.createLiteral(), call)
53
+ return this
54
+ } else {
55
+ throw Selfie .system.fs.assertFailed(" Can't call `toMatchDisk_TODO` in ${Mode .readonly} mode!" )
56
+ }
57
+ }
58
+ override fun facet (facet : String ): StringFacet = StringSelfie (actual, disk, listOf (facet))
59
+ override fun facets (vararg facets : String ): StringFacet =
60
+ StringSelfie (actual, disk, facets.toList())
61
+ override fun facetBinary (facet : String ) = BinarySelfie (actual, disk, facet)
62
+ }
63
+
64
+ interface FluentFacet {
65
+ /* * Extract a single facet from a snapshot in order to do an inline snapshot. */
66
+ fun facet (facet : String ): StringFacet
67
+ /* * Extract multiple facets from a snapshot in order to do an inline snapshot. */
68
+ fun facets (vararg facets : String ): StringFacet
69
+ fun facetBinary (facet : String ): BinaryFacet
70
+ }
71
+
72
+ interface StringFacet : FluentFacet {
73
+ fun toBe (expected : String ): String
74
+ fun toBe_TODO (unusedArg : Any? ): String = toBe_TODO()
75
+ fun toBe_TODO (): String
76
+ }
77
+
78
+ interface BinaryFacet : FluentFacet {
79
+ fun toBeBase64 (expected : String ): ByteArray
80
+ fun toBeBase64_TODO (unusedArg : Any? ): ByteArray = toBeBase64_TODO()
81
+ fun toBeBase64_TODO (): ByteArray
82
+ fun toBeFile (subpath : String ): ByteArray
83
+ fun toBeFile_TODO (subpath : String ): ByteArray
84
+ }
85
+
86
+ class BinarySelfie (actual : Snapshot , disk : DiskStorage , private val onlyFacet : String ) :
87
+ DiskSelfie (actual, disk), BinaryFacet {
88
+ init {
89
+ check(actual.subjectOrFacetMaybe(onlyFacet)?.isBinary == true ) {
90
+ " The facet $onlyFacet was not found in the snapshot, or it was not a binary facet."
91
+ }
92
+ }
93
+ private fun actualBytes () = actual.subjectOrFacet(onlyFacet).valueBinary()
94
+ override fun toMatchDisk (sub : String ): BinarySelfie {
95
+ super .toMatchDisk(sub)
96
+ return this
97
+ }
98
+ override fun toMatchDisk_TODO (sub : String ): BinarySelfie {
99
+ super .toMatchDisk_TODO(sub)
100
+ return this
101
+ }
102
+
103
+ @OptIn(ExperimentalEncodingApi ::class )
104
+ private fun actualString (): String = Base64 .Mime .encode(actualBytes()).replace(" \r " , " " )
105
+ override fun toBeBase64_TODO (): ByteArray {
106
+ toBeDidntMatch(null , actualString(), LiteralString )
107
+ return actualBytes()
108
+ }
109
+
110
+ @OptIn(ExperimentalEncodingApi ::class )
111
+ override fun toBeBase64 (expected : String ): ByteArray {
112
+ val expectedBytes = Base64 .Mime .decode(expected)
113
+ val actualBytes = actualBytes()
114
+ return if (expectedBytes.contentEquals(actualBytes)) Selfie .system.checkSrc(actualBytes)
115
+ else {
116
+ toBeDidntMatch(expected, actualString(), LiteralString )
117
+ return actualBytes()
118
+ }
119
+ }
120
+ override fun toBeFile_TODO (subpath : String ): ByteArray {
121
+ return toBeFileImpl(subpath, true )
122
+ }
123
+ override fun toBeFile (subpath : String ): ByteArray {
124
+ return toBeFileImpl(subpath, false )
125
+ }
126
+ private fun resolvePath (subpath : String ) = Selfie .system.layout.rootFolder.resolveFile(subpath)
127
+ private fun toBeFileImpl (subpath : String , isTodo : Boolean ): ByteArray {
128
+ val call = recordCall(false )
129
+ val writable = Selfie .system.mode.canWrite(isTodo, call, Selfie .system)
130
+ val actualBytes = actualBytes()
131
+ if (writable) {
132
+ if (isTodo) {
133
+ Selfie .system.writeInline(TodoStub .toBeFile.createLiteral(), call)
134
+ }
135
+ Selfie .system.fs.fileWriteBinary(resolvePath(subpath), actualBytes)
136
+ return actualBytes
137
+ } else {
138
+ if (isTodo) {
139
+ throw Selfie .system.fs.assertFailed(" Can't call `toBeFile_TODO` in ${Mode .readonly} mode!" )
140
+ } else {
141
+ val expected = Selfie .system.fs.fileReadBinary(resolvePath(subpath))
142
+ if (expected.contentEquals(actualBytes)) {
143
+ return actualBytes
144
+ } else {
145
+ throw Selfie .system.fs.assertFailed(
146
+ Selfie .system.mode.msgSnapshotMismatch(), expected, actualBytes)
147
+ }
148
+ }
149
+ }
150
+ }
151
+ }
152
+
153
+ class StringSelfie (
154
+ actual : Snapshot ,
155
+ disk : DiskStorage ,
35
156
private val onlyFacets : Collection <String >? = null
36
- ) {
157
+ ) : DiskSelfie(actual, disk), StringFacet {
37
158
init {
38
159
if (onlyFacets != null ) {
39
160
check(onlyFacets.all { it == " " || actual.facets.containsKey(it) }) {
@@ -47,10 +168,14 @@ internal constructor(
47
168
}
48
169
}
49
170
}
50
- /* * Extract a single facet from a snapshot in order to do an inline snapshot. */
51
- fun facet (facet : String ) = LiteralStringSelfie (actual, listOf (facet))
52
- /* * Extract a multiple facets from a snapshot in order to do an inline snapshot. */
53
- fun facets (vararg facets : String ) = LiteralStringSelfie (actual, facets.toList())
171
+ override fun toMatchDisk (sub : String ): StringSelfie {
172
+ super .toMatchDisk(sub)
173
+ return this
174
+ }
175
+ override fun toMatchDisk_TODO (sub : String ): StringSelfie {
176
+ super .toMatchDisk_TODO(sub)
177
+ return this
178
+ }
54
179
55
180
@OptIn(ExperimentalEncodingApi ::class )
56
181
private fun actualString (): String {
@@ -70,42 +195,14 @@ internal constructor(
70
195
})
71
196
}
72
197
}
73
-
74
- @JvmOverloads
75
- fun toBe_TODO (unusedArg : Any? = null) = toBeDidntMatch(null , actualString(), LiteralString )
76
- fun toBe (expected : String ): String {
198
+ override fun toBe_TODO (): String = toBeDidntMatch(null , actualString(), LiteralString )
199
+ override fun toBe (expected : String ): String {
77
200
val actualString = actualString()
78
201
return if (actualString == expected) Selfie .system.checkSrc(actualString)
79
202
else toBeDidntMatch(expected, actualString, LiteralString )
80
203
}
81
204
}
82
205
83
- class DiskSelfie internal constructor(actual : Snapshot , val disk : DiskStorage ) :
84
- LiteralStringSelfie (actual) {
85
- @JvmOverloads
86
- fun toMatchDisk (sub : String = ""): DiskSelfie {
87
- val call = recordCall(false )
88
- if (Selfie .system.mode.canWrite(false , call, Selfie .system)) {
89
- disk.writeDisk(actual, sub, call)
90
- } else {
91
- assertEqual(disk.readDisk(sub, call), actual, Selfie .system)
92
- }
93
- return this
94
- }
95
-
96
- @JvmOverloads
97
- fun toMatchDisk_TODO (sub : String = ""): DiskSelfie {
98
- val call = recordCall(false )
99
- if (Selfie .system.mode.canWrite(true , call, Selfie .system)) {
100
- disk.writeDisk(actual, sub, call)
101
- Selfie .system.writeInline(DiskSnapshotTodo .createLiteral(), call)
102
- return this
103
- } else {
104
- throw Selfie .system.fs.assertFailed(" Can't call `toMatchDisk_TODO` in ${Mode .readonly} mode!" )
105
- }
106
- }
107
- }
108
-
109
206
/* *
110
207
* Returns a serialized form of only the given facets if they are available, silently omits missing
111
208
* facets.
0 commit comments