106 lines
4.4 KiB
Swift
106 lines
4.4 KiB
Swift
//===----------------------------------------------------------------------===//
|
|
// Copyright © 2025-2026 Apple Inc. and the Containerization project authors.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// https://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
import Foundation
|
|
import SystemPackage
|
|
import Testing
|
|
|
|
@testable import ContainerizationEXT4
|
|
|
|
struct Ext4UnpackerTests {
|
|
// alpine image
|
|
let indexSHA: String = "ad59e9f71edceca7b1ac7c642410858489b743c97233b0a26a5e2098b1443762"
|
|
let fsPath = FilePath(
|
|
FileManager.default.uniqueTemporaryDirectory()
|
|
.appendingPathComponent("ext4.unpacked.oci.img.delme", isDirectory: false))
|
|
|
|
final class MockEXT4Unpacker {
|
|
static func Unpack(index: String, fsPath: FilePath) async throws {
|
|
let fs = try EXT4.Formatter(fsPath)
|
|
let bundle = Bundle.module
|
|
guard let indexPath = bundle.url(forResource: index, withExtension: nil) else {
|
|
throw NSError(domain: "indexPath not found", code: 1)
|
|
}
|
|
let indexData = try Data(contentsOf: indexPath)
|
|
guard let indexDict = try JSONSerialization.jsonObject(with: indexData, options: []) as? [String: Any]
|
|
else {
|
|
throw NSError(domain: "indexDict could not be loaded as json", code: 1)
|
|
}
|
|
guard let manifests = indexDict["manifests"] as? [[String: Any]] else {
|
|
throw NSError(domain: "manifests field in index not found", code: 1)
|
|
}
|
|
guard let digest = manifests[0]["digest"] as? String else {
|
|
throw NSError(domain: "digest field not found in index", code: 1)
|
|
}
|
|
guard
|
|
let manifestPath = bundle.url(
|
|
forResource: String(digest.dropFirst("sha256:".count)), withExtension: nil)
|
|
else {
|
|
throw NSError(domain: "manifestPath not found", code: 1)
|
|
}
|
|
let manifestData = try Data(contentsOf: manifestPath)
|
|
guard let manifestDict = try JSONSerialization.jsonObject(with: manifestData, options: []) as? [String: Any]
|
|
else {
|
|
throw NSError(domain: "manifestDict could not be loaded as json", code: 1)
|
|
}
|
|
guard let layers = manifestDict["layers"] as? [[String: Any]] else {
|
|
throw NSError(domain: "layers field in manifests not found", code: 1)
|
|
}
|
|
for layer in layers {
|
|
guard let layerDigestWithSHA = layer["digest"] as? String else {
|
|
throw NSError(domain: "digest field not found in layer", code: 1)
|
|
}
|
|
let layerDigest = String(layerDigestWithSHA.dropFirst("sha256:".count))
|
|
guard let layerPath = bundle.url(forResource: layerDigest, withExtension: nil) else {
|
|
throw NSError(domain: "layer \(layerDigest) not found", code: 1)
|
|
}
|
|
try await fs.unpack(source: layerPath)
|
|
}
|
|
try fs.close()
|
|
}
|
|
}
|
|
|
|
@Test func eXT4Unpacker() async throws {
|
|
try await MockEXT4Unpacker.Unpack(index: self.indexSHA, fsPath: self.fsPath)
|
|
let ext4 = try EXT4.EXT4Reader(blockDevice: self.fsPath)
|
|
let children = try ext4.children(of: EXT4.RootInode)
|
|
#expect(
|
|
Set(children.map { $0.0 })
|
|
== Set([
|
|
".",
|
|
"..",
|
|
"media",
|
|
"var",
|
|
"opt",
|
|
"lost+found",
|
|
"tmp",
|
|
"mnt",
|
|
"sys",
|
|
"usr",
|
|
"srv",
|
|
"root",
|
|
"etc",
|
|
"dev",
|
|
"proc",
|
|
"run",
|
|
"home",
|
|
"bin",
|
|
"lib",
|
|
"sbin",
|
|
]))
|
|
}
|
|
}
|