return {"invalid ", Keys[Key], " section"};
}
-static llvm::SmallString<128> getSerializeErrorMsg(TBDKey Key) {
- return {"missing ", Keys[Key], " information"};
-}
-
class JSONStubError : public llvm::ErrorInfo<llvm::json::ParseError> {
public:
JSONStubError(Twine ErrMsg) : Message(ErrMsg.str()) {}
}
return std::move(IF);
}
-
-namespace {
-
-template <typename ContainerT = Array>
-bool insertNonEmptyValues(Object &Obj, TBDKey Key, ContainerT &&Contents) {
- if (Contents.empty())
- return false;
- Obj[Keys[Key]] = std::move(Contents);
- return true;
-}
-
-std::string getFormattedStr(const MachO::Target &Targ) {
- std::string PlatformStr = Targ.Platform == PLATFORM_MACCATALYST
- ? "maccatalyst"
- : getOSAndEnvironmentName(Targ.Platform);
- return (getArchitectureName(Targ.Arch) + "-" + PlatformStr).str();
-}
-
-template <typename AggregateT>
-std::vector<std::string> serializeTargets(const AggregateT Targets,
- const TargetList &ActiveTargets) {
- std::vector<std::string> TargetsStr;
- if (Targets.size() == ActiveTargets.size())
- return TargetsStr;
-
- llvm::for_each(Targets, [&TargetsStr](const MachO::Target &Target) {
- TargetsStr.emplace_back(getFormattedStr(Target));
- });
- return TargetsStr;
-}
-
-Array serializeTargetInfo(const TargetList &ActiveTargets) {
- Array Targets;
- for (const auto Targ : ActiveTargets) {
- Object TargetInfo;
- TargetInfo[Keys[TBDKey::Deployment]] = Targ.MinDeployment.getAsString();
- TargetInfo[Keys[TBDKey::Target]] = getFormattedStr(Targ);
- Targets.emplace_back(std::move(TargetInfo));
- }
- return Targets;
-}
-
-template <typename ValueT, typename EntryT = ValueT>
-Array serializeScalar(TBDKey Key, ValueT Value, ValueT Default = ValueT()) {
- if (Value == Default)
- return {};
- Array Container;
- Object ScalarObj({Object::KV({Keys[Key], EntryT(Value)})});
-
- Container.emplace_back(std::move(ScalarObj));
- return Container;
-}
-
-using TargetsToValuesMap =
- std::map<std::vector<std::string>, std::vector<std::string>>;
-
-template <typename AggregateT = TargetsToValuesMap>
-Array serializeAttrToTargets(AggregateT &Entries, TBDKey Key) {
- Array Container;
- for (const auto &[Targets, Values] : Entries) {
- Object Obj;
- insertNonEmptyValues(Obj, TBDKey::Targets, std::move(Targets));
- Obj[Keys[Key]] = Values;
- Container.emplace_back(std::move(Obj));
- }
- return Container;
-}
-
-template <typename ValueT = std::string,
- typename AggregateT = std::vector<std::pair<MachO::Target, ValueT>>>
-Array serializeField(TBDKey Key, const AggregateT &Values,
- const TargetList &ActiveTargets, bool IsArray = true) {
- std::map<ValueT, std::set<MachO::Target>> Entries;
- for (const auto &[Target, Val] : Values)
- Entries[Val].insert(Target);
-
- if (!IsArray) {
- std::map<std::vector<std::string>, std::string> FinalEntries;
- for (const auto &[Val, Targets] : Entries)
- FinalEntries[serializeTargets(Targets, ActiveTargets)] = Val;
- return serializeAttrToTargets(FinalEntries, Key);
- }
-
- TargetsToValuesMap FinalEntries;
- for (const auto &[Val, Targets] : Entries)
- FinalEntries[serializeTargets(Targets, ActiveTargets)].emplace_back(Val);
- return serializeAttrToTargets(FinalEntries, Key);
-}
-
-Array serializeField(TBDKey Key, const std::vector<InterfaceFileRef> &Values,
- const TargetList &ActiveTargets) {
- TargetsToValuesMap FinalEntries;
- for (const auto &Ref : Values) {
- TargetList Targets{Ref.targets().begin(), Ref.targets().end()};
- FinalEntries[serializeTargets(Targets, ActiveTargets)].emplace_back(
- Ref.getInstallName());
- }
- return serializeAttrToTargets(FinalEntries, Key);
-}
-
-struct SymbolFields {
- struct SymbolTypes {
- std::vector<StringRef> Weaks;
- std::vector<StringRef> Globals;
- std::vector<StringRef> TLV;
- std::vector<StringRef> ObjCClasses;
- std::vector<StringRef> IVars;
- std::vector<StringRef> EHTypes;
-
- bool empty() const {
- return Weaks.empty() && Globals.empty() && TLV.empty() &&
- ObjCClasses.empty() && IVars.empty() && EHTypes.empty();
- }
- };
- SymbolTypes Data;
- SymbolTypes Text;
-};
-
-Array serializeSymbols(InterfaceFile::const_filtered_symbol_range Symbols,
- const TargetList &ActiveTargets) {
- auto AssignForSymbolType = [](SymbolFields::SymbolTypes &Assignment,
- const Symbol *Sym) {
- switch (Sym->getKind()) {
- case SymbolKind::ObjectiveCClass:
- Assignment.ObjCClasses.emplace_back(Sym->getName());
- return;
- case SymbolKind::ObjectiveCClassEHType:
- Assignment.EHTypes.emplace_back(Sym->getName());
- return;
- case SymbolKind::ObjectiveCInstanceVariable:
- Assignment.IVars.emplace_back(Sym->getName());
- return;
- case SymbolKind::GlobalSymbol: {
- if (Sym->isWeakReferenced() || Sym->isWeakDefined())
- Assignment.Weaks.emplace_back(Sym->getName());
- else if (Sym->isThreadLocalValue())
- Assignment.TLV.emplace_back(Sym->getName());
- else
- Assignment.Globals.emplace_back(Sym->getName());
- return;
- }
- }
- };
-
- std::map<std::vector<std::string>, SymbolFields> Entries;
- for (const auto *Sym : Symbols) {
- std::set<MachO::Target> Targets{Sym->targets().begin(),
- Sym->targets().end()};
- auto JSONTargets = serializeTargets(Targets, ActiveTargets);
- if (Sym->isData())
- AssignForSymbolType(Entries[std::move(JSONTargets)].Data, Sym);
- else if (Sym->isText())
- AssignForSymbolType(Entries[std::move(JSONTargets)].Text, Sym);
- else
- llvm_unreachable("unexpected symbol type");
- }
-
- auto InsertSymbolsToJSON = [](Object &SymSection, TBDKey SegmentKey,
- SymbolFields::SymbolTypes &SymField) {
- if (SymField.empty())
- return;
- Object Segment;
- insertNonEmptyValues(Segment, TBDKey::Globals, std::move(SymField.Globals));
- insertNonEmptyValues(Segment, TBDKey::ThreadLocal, std::move(SymField.TLV));
- insertNonEmptyValues(Segment, TBDKey::Weak, std::move(SymField.Weaks));
- insertNonEmptyValues(Segment, TBDKey::ObjCClass,
- std::move(SymField.ObjCClasses));
- insertNonEmptyValues(Segment, TBDKey::ObjCEHType,
- std::move(SymField.EHTypes));
- insertNonEmptyValues(Segment, TBDKey::ObjCIvar, std::move(SymField.IVars));
- insertNonEmptyValues(SymSection, SegmentKey, std::move(Segment));
- };
-
- Array SymbolSection;
- for (auto &[Targets, Fields] : Entries) {
- Object AllSyms;
- insertNonEmptyValues(AllSyms, TBDKey::Targets, std::move(Targets));
- InsertSymbolsToJSON(AllSyms, TBDKey::Data, Fields.Data);
- InsertSymbolsToJSON(AllSyms, TBDKey::Text, Fields.Text);
- SymbolSection.emplace_back(std::move(AllSyms));
- }
-
- return SymbolSection;
-}
-
-Array serializeFlags(const InterfaceFile *File) {
- // TODO: Give all Targets the same flags for now.
- Array Flags;
- if (!File->isTwoLevelNamespace())
- Flags.emplace_back("flat_namespace");
- if (!File->isApplicationExtensionSafe())
- Flags.emplace_back("not_app_extension_safe");
- return serializeScalar(TBDKey::Attributes, std::move(Flags));
-}
-
-Expected<Object> serializeIF(const InterfaceFile *File) {
- Object Library;
-
- // Handle required keys.
- TargetList ActiveTargets{File->targets().begin(), File->targets().end()};
- if (!insertNonEmptyValues(Library, TBDKey::TargetInfo,
- serializeTargetInfo(ActiveTargets)))
- return make_error<JSONStubError>(getSerializeErrorMsg(TBDKey::TargetInfo));
-
- Array Name = serializeScalar<StringRef>(TBDKey::Name, File->getInstallName());
- if (!insertNonEmptyValues(Library, TBDKey::InstallName, std::move(Name)))
- return make_error<JSONStubError>(getSerializeErrorMsg(TBDKey::InstallName));
-
- // Handle optional keys.
- Array Flags = serializeFlags(File);
- insertNonEmptyValues(Library, TBDKey::Flags, std::move(Flags));
-
- Array CurrentV = serializeScalar<PackedVersion, std::string>(
- TBDKey::Version, File->getCurrentVersion(), PackedVersion(1, 0, 0));
- insertNonEmptyValues(Library, TBDKey::CurrentVersion, std::move(CurrentV));
-
- Array CompatV = serializeScalar<PackedVersion, std::string>(
- TBDKey::Version, File->getCompatibilityVersion(), PackedVersion(1, 0, 0));
- insertNonEmptyValues(Library, TBDKey::CompatibilityVersion,
- std::move(CompatV));
-
- Array SwiftABI = serializeScalar<uint8_t, int64_t>(
- TBDKey::ABI, File->getSwiftABIVersion(), 0u);
- insertNonEmptyValues(Library, TBDKey::SwiftABI, std::move(SwiftABI));
-
- Array RPaths = serializeField(TBDKey::Paths, File->rpaths(), ActiveTargets);
- insertNonEmptyValues(Library, TBDKey::RPath, std::move(RPaths));
-
- Array Umbrellas = serializeField(TBDKey::Umbrella, File->umbrellas(),
- ActiveTargets, /*IsArray=*/false);
- insertNonEmptyValues(Library, TBDKey::ParentUmbrella, std::move(Umbrellas));
-
- Array Clients =
- serializeField(TBDKey::Clients, File->allowableClients(), ActiveTargets);
- insertNonEmptyValues(Library, TBDKey::AllowableClients, std::move(Clients));
-
- Array ReexportLibs =
- serializeField(TBDKey::Names, File->reexportedLibraries(), ActiveTargets);
- insertNonEmptyValues(Library, TBDKey::ReexportLibs, std::move(ReexportLibs));
-
- // Handle symbols.
- Array Exports = serializeSymbols(File->exports(), ActiveTargets);
- insertNonEmptyValues(Library, TBDKey::Exports, std::move(Exports));
-
- Array Reexports = serializeSymbols(File->reexports(), ActiveTargets);
- insertNonEmptyValues(Library, TBDKey::Reexports, std::move(Reexports));
-
- if (!File->isTwoLevelNamespace()) {
- Array Undefineds = serializeSymbols(File->undefineds(), ActiveTargets);
- insertNonEmptyValues(Library, TBDKey::Undefineds, std::move(Undefineds));
- }
-
- return std::move(Library);
-}
-
-Expected<Object> getJSON(const InterfaceFile *File) {
- assert(File->getFileType() == FileType::TBD_V5 &&
- "unexpected json file format version");
- Object Root;
-
- auto MainLibOrErr = serializeIF(File);
- if (!MainLibOrErr)
- return MainLibOrErr;
- Root[Keys[TBDKey::MainLibrary]] = std::move(*MainLibOrErr);
- Array Documents;
- for (const auto &Doc : File->documents()) {
- auto LibOrErr = serializeIF(Doc.get());
- if (!LibOrErr)
- return LibOrErr;
- Documents.emplace_back(std::move(*LibOrErr));
- }
-
- Root[Keys[TBDKey::TBDVersion]] = 5;
- insertNonEmptyValues(Root, TBDKey::Documents, std::move(Documents));
- return std::move(Root);
-}
-
-} // namespace
-
-Error MachO::serializeInterfaceFileToJSON(raw_ostream &OS,
- const InterfaceFile &File,
- bool Compact) {
- auto TextFile = getJSON(&File);
- if (!TextFile)
- return TextFile.takeError();
- if (Compact)
- OS << formatv("{0}", Value(std::move(*TextFile))) << "\n";
- else
- OS << formatv("{0:2}", Value(std::move(*TextFile))) << "\n";
- return Error::success();
-}
std::equal(Exports.begin(), Exports.end(), std::begin(ExpectedExports)));
}
-TEST(TBDv5, WriteFile) {
- static const char TBDv5File[] = R"({
-"tapi_tbd_version": 5,
-"main_library": {
- "target_info": [
- {
- "target": "x86_64-macos",
- "min_deployment": "10.14"
- },
- {
- "target": "arm64-macos",
- "min_deployment": "10.14"
- },
- {
- "target": "arm64-maccatalyst",
- "min_deployment": "12.1"
- }
- ],
- "install_names": [
- {
- "name": "@rpath/S/L/F/Foo.framework/Foo"
- }
- ],
- "current_versions": [
- {
- "version": "1.2"
- }
- ],
- "compatibility_versions": [
- { "version": "1.1" }
- ],
- "flags": [
- {
- "attributes": [
- "flat_namespace"
- ]
- }
- ],
- "rpaths": [
- {
- "targets": [
- "x86_64-macos"
- ],
- "paths": [
- "@executable_path/.../Frameworks"
- ]
- }
- ],
- "parent_umbrellas": [
- {
- "umbrella": "System"
- }
- ],
- "allowable_clients": [
- {
- "clients": [
- "ClientA",
- "ClientB"
- ]
- }
- ],
- "reexported_libraries": [
- {
- "names": [
- "/u/l/l/libfoo.dylib",
- "/u/l/l/libbar.dylib"
- ]
- }
- ],
- "exported_symbols": [
- {
- "targets": [
- "x86_64-macos",
- "arm64-macos"
- ],
- "data": {
- "global": [
- "_global"
- ],
- "objc_class": [
- "ClassA"
- ],
- "weak": [],
- "thread_local": []
- },
- "text": {
- "global": [
- "_func"
- ],
- "weak": [],
- "thread_local": []
- }
- },
- {
- "targets": [
- "x86_64-macos"
- ],
- "data": {
- "global": [
- "_globalVar"
- ],
- "objc_class": [
- "ClassData"
- ],
- "objc_eh_type": [
- "ClassA",
- "ClassB"
- ],
- "objc_ivar": [
- "ClassA.ivar1",
- "ClassA.ivar2",
- "ClassC.ivar1"
- ]
- },
- "text": {
- "global": [
- "_funcFoo"
- ]
- }
- }
- ],
- "reexported_symbols": [
- {
- "data": {
- "global": [
- "_globalRe"
- ],
- "objc_class": [
- "ClassRexport"
- ]
- },
- "text": {
- "global": [
- "_funcA"
- ]
- }
- }
- ],
- "undefined_symbols": [
- {
- "targets": [
- "x86_64-macos"
- ],
- "data": {
- "global": [
- "_globalBind"
- ],
- "weak": [
- "referenced_sym"
- ]
- }
- }
- ]
-}})";
-
- InterfaceFile File;
- File.setFileType(FileType::TBD_V5);
-
- TargetList AllTargets = {
- Target(AK_x86_64, PLATFORM_MACOS, VersionTuple(10, 14)),
- Target(AK_arm64, PLATFORM_MACOS, VersionTuple(10, 14)),
- Target(AK_arm64, PLATFORM_MACCATALYST, VersionTuple(12, 1)),
- };
- File.addTargets(AllTargets);
- File.setInstallName("@rpath/S/L/F/Foo.framework/Foo");
- File.setCurrentVersion(PackedVersion(1, 2, 0));
- File.setCompatibilityVersion(PackedVersion(1, 1, 0));
- File.addRPath(AllTargets[0], "@executable_path/.../Frameworks");
-
- for (const auto &Targ : AllTargets) {
- File.addParentUmbrella(Targ, "System");
- File.addAllowableClient("ClientA", Targ);
- File.addAllowableClient("ClientB", Targ);
- File.addReexportedLibrary("/u/l/l/libfoo.dylib", Targ);
- File.addReexportedLibrary("/u/l/l/libbar.dylib", Targ);
- }
-
- SymbolFlags Flags = SymbolFlags::None;
- // Exports.
- File.addSymbol(SymbolKind::GlobalSymbol, "_global",
- {AllTargets[0], AllTargets[1]}, Flags | SymbolFlags::Data);
- File.addSymbol(SymbolKind::GlobalSymbol, "_func",
- {AllTargets[0], AllTargets[1]}, Flags | SymbolFlags::Text);
- File.addSymbol(SymbolKind::ObjectiveCClass, "ClassA",
- {AllTargets[0], AllTargets[1]}, Flags | SymbolFlags::Data);
- File.addSymbol(SymbolKind::GlobalSymbol, "_funcFoo", {AllTargets[0]},
- Flags | SymbolFlags::Text);
- File.addSymbol(SymbolKind::GlobalSymbol, "_globalVar", {AllTargets[0]},
- Flags | SymbolFlags::Data);
- File.addSymbol(SymbolKind::ObjectiveCClass, "ClassData", {AllTargets[0]},
- Flags | SymbolFlags::Data);
- File.addSymbol(SymbolKind::ObjectiveCClassEHType, "ClassA", {AllTargets[0]},
- Flags | SymbolFlags::Data);
- File.addSymbol(SymbolKind::ObjectiveCClassEHType, "ClassB", {AllTargets[0]},
- Flags | SymbolFlags::Data);
- File.addSymbol(SymbolKind::ObjectiveCInstanceVariable, "ClassA.ivar1",
- {AllTargets[0]}, Flags | SymbolFlags::Data);
- File.addSymbol(SymbolKind::ObjectiveCInstanceVariable, "ClassA.ivar2",
- {AllTargets[0]}, Flags | SymbolFlags::Data);
- File.addSymbol(SymbolKind::ObjectiveCInstanceVariable, "ClassC.ivar1",
- {AllTargets[0]}, Flags | SymbolFlags::Data);
-
- // Reexports.
- Flags = SymbolFlags::Rexported;
- File.addSymbol(SymbolKind::GlobalSymbol, "_globalRe", AllTargets,
- Flags | SymbolFlags::Data);
- File.addSymbol(SymbolKind::GlobalSymbol, "_funcA", AllTargets,
- Flags | SymbolFlags::Text);
- File.addSymbol(SymbolKind::ObjectiveCClass, "ClassRexport", AllTargets,
- Flags | SymbolFlags::Data);
-
- // Undefineds.
- Flags = SymbolFlags::Undefined;
- File.addSymbol(SymbolKind::GlobalSymbol, "_globalBind", {AllTargets[0]},
- Flags | SymbolFlags::Data);
- File.addSymbol(SymbolKind::GlobalSymbol, "referenced_sym", {AllTargets[0]},
- Flags | SymbolFlags::Data | SymbolFlags::WeakReferenced);
-
- File.setTwoLevelNamespace(false);
- File.setApplicationExtensionSafe(true);
-
- // Write out file then process it back into IF and compare equality
- // against TBDv5File.
- SmallString<4096> Buffer;
- raw_svector_ostream OS(Buffer);
- Error Result = TextAPIWriter::writeToStream(OS, File);
- EXPECT_FALSE(Result);
-
- Expected<TBDFile> Input =
- TextAPIReader::get(MemoryBufferRef(TBDv5File, "Input.tbd"));
- EXPECT_TRUE(!!Input);
- TBDFile InputFile = std::move(Input.get());
-
- Expected<TBDFile> Output =
- TextAPIReader::get(MemoryBufferRef(Buffer, "Output.tbd"));
- EXPECT_TRUE(!!Output);
- TBDFile OutputFile = std::move(Output.get());
- EXPECT_EQ(*InputFile, *OutputFile);
-}
-
-TEST(TBDv5, WriteMultipleDocuments) {
- static const char TBDv5File[] = R"({
-"tapi_tbd_version": 5,
-"main_library": {
- "target_info": [
- {
- "target": "armv7-ios",
- "min_deployment": "11.0"
- }
- ],
- "install_names":[
- { "name":"/S/L/F/Foo.framework/Foo" }
- ],
- "reexported_libraries": [
- { "names": ["/u/l/l/libfoo.dylib"]
- }
- ]
-},
-"libraries": [
- {
- "target_info": [
- {
- "target": "armv7-ios",
- "min_deployment": "11.0"
- },
- {
- "target": "armv7s-ios",
- "min_deployment": "11.0"
- }
- ],
- "install_names":[
- { "name":"/u/l/l/libfoo.dylib" }
- ],
- "current_versions": [
- {
- "version": "2.1.1"
- }
- ],
- "rpaths": [
- {
- "targets": [
- "armv7-ios"
- ],
- "paths": [
- "@executable_path/.../Frameworks"
- ]
- }],
- "reexported_libraries": [ { "names": ["@rpath/libfoo.dylib"] } ],
- "flags":[
- { "attributes": ["not_app_extension_safe"] }
- ],
- "exported_symbols": [
- {
- "text": {
- "global": [ "_funcFoo" ]
- }
- }
- ]
- },
- {
- "target_info": [
- {
- "target": "armv7-ios",
- "min_deployment": "11.0"
- }
- ],
- "install_names":[
- { "name":"@rpath/libfoo.dylib" }
- ],
- "exported_symbols": [
- {
- "data": {
- "global": [ "_varFooBaz" ]
- }
- }
- ]
- }
-]})";
-
- InterfaceFile File;
- File.setFileType(FileType::TBD_V5);
-
- TargetList AllTargets = {
- Target(AK_armv7, PLATFORM_IOS, VersionTuple(11, 0)),
- Target(AK_armv7s, PLATFORM_IOS, VersionTuple(11, 0)),
- };
- File.setInstallName("/S/L/F/Foo.framework/Foo");
- File.addTarget(AllTargets[0]);
- File.setCurrentVersion(PackedVersion(1, 0, 0));
- File.setCompatibilityVersion(PackedVersion(1, 0, 0));
- File.addReexportedLibrary("/u/l/l/libfoo.dylib", AllTargets[0]);
- File.setTwoLevelNamespace();
- File.setApplicationExtensionSafe(true);
-
- InterfaceFile NestedFile;
- NestedFile.setFileType(FileType::TBD_V5);
- NestedFile.setInstallName("/u/l/l/libfoo.dylib");
- NestedFile.addTargets(AllTargets);
- NestedFile.setCompatibilityVersion(PackedVersion(1, 0, 0));
- NestedFile.setTwoLevelNamespace();
- NestedFile.setApplicationExtensionSafe(false);
- NestedFile.setCurrentVersion(PackedVersion(2, 1, 1));
- NestedFile.addRPath(AllTargets[0], "@executable_path/.../Frameworks");
- for (const auto &Targ : AllTargets)
- NestedFile.addReexportedLibrary("@rpath/libfoo.dylib", Targ);
- NestedFile.addSymbol(SymbolKind::GlobalSymbol, "_funcFoo", AllTargets,
- SymbolFlags::Text);
- File.addDocument(std::make_shared<InterfaceFile>(std::move(NestedFile)));
-
- InterfaceFile NestedFileB;
- NestedFileB.setFileType(FileType::TBD_V5);
- NestedFileB.setInstallName("@rpath/libfoo.dylib");
- NestedFileB.addTarget(AllTargets[0]);
- NestedFileB.setCompatibilityVersion(PackedVersion(1, 0, 0));
- NestedFileB.setCurrentVersion(PackedVersion(1, 0, 0));
- NestedFileB.setTwoLevelNamespace();
- NestedFileB.setApplicationExtensionSafe(true);
- NestedFileB.addSymbol(SymbolKind::GlobalSymbol, "_varFooBaz", AllTargets,
- SymbolFlags::Data);
- File.addDocument(std::make_shared<InterfaceFile>(std::move(NestedFileB)));
-
- // Write out file then process it back into IF and compare equality
- // against TBDv5File.
- SmallString<4096> Buffer;
- raw_svector_ostream OS(Buffer);
- Error Result = TextAPIWriter::writeToStream(OS, File, /*Compact=*/true);
- EXPECT_FALSE(Result);
-
- Expected<TBDFile> Input =
- TextAPIReader::get(MemoryBufferRef(TBDv5File, "Input.tbd"));
- EXPECT_TRUE(!!Input);
- TBDFile InputFile = std::move(Input.get());
-
- Expected<TBDFile> Output =
- TextAPIReader::get(MemoryBufferRef(Buffer, "Output.tbd"));
- EXPECT_TRUE(!!Output);
- TBDFile OutputFile = std::move(Output.get());
- EXPECT_EQ(*InputFile, *OutputFile);
-}
-
-TEST(TBDv5, Target_Simulator) {
- static const char TBDv5File[] = R"({
-"tapi_tbd_version": 5,
-"main_library": {
- "target_info": [
- {
- "target": "arm64-ios-simulator",
- "min_deployment": "11.0"
- },
- {
- "target": "x86_64-ios-simulator",
- "min_deployment": "11.3"
- }
- ],
- "install_names":[
- { "name":"/S/L/F/Foo.framework/Foo" }
- ]
-}})";
-
- Expected<TBDFile> Result =
- TextAPIReader::get(MemoryBufferRef(TBDv5File, "Test.tbd"));
- EXPECT_TRUE(!!Result);
- TBDFile File = std::move(Result.get());
- EXPECT_EQ(FileType::TBD_V5, File->getFileType());
- TargetList ExpectedTargets = {
- Target(AK_x86_64, PLATFORM_IOSSIMULATOR, VersionTuple(11, 3)),
- Target(AK_arm64, PLATFORM_IOSSIMULATOR, VersionTuple(11, 0)),
- };
- TargetList Targets{File->targets().begin(), File->targets().end()};
- llvm::sort(Targets);
- EXPECT_EQ(Targets, ExpectedTargets);
-
- SmallString<4096> Buffer;
- raw_svector_ostream OS(Buffer);
- Error WriteResult = TextAPIWriter::writeToStream(OS, *File);
- EXPECT_TRUE(!WriteResult);
-
- Expected<TBDFile> Output =
- TextAPIReader::get(MemoryBufferRef(Buffer, "Output.tbd"));
- EXPECT_TRUE(!!Output);
- TBDFile WriteResultFile = std::move(Output.get());
- EXPECT_EQ(*File, *WriteResultFile);
-}
-
-TEST(TBDv5, MisspelledKey) {
- static const char TBDv5File[] = R"({
-"tapi_tbd_version": 5,
-"main_library": {
- "target_info": [
- {
- "target": "arm64-ios-simulator",
- "min_deployment": "11.0"
- }
- ],
- "intall_names":[
- { "name":"/S/L/F/Foo.framework/Foo" }
- ]
-}})";
-
- Expected<TBDFile> Result =
- TextAPIReader::get(MemoryBufferRef(TBDv5File, "Test.tbd"));
- EXPECT_FALSE(!!Result);
- std::string ErrorMessage = toString(Result.takeError());
- EXPECT_EQ("invalid install_names section\n", ErrorMessage);
-}
-
-TEST(TBDv5, InvalidVersion) {
- static const char TBDv5File[] = R"({
-"tapi_tbd_version": 11,
-"main_library": {
- "target_info": [
- {
- "target": "arm64-ios-simulator",
- "min_deployment": "11.0"
- }
- ],
- "install_names":[
- { "name":"/S/L/F/Foo.framework/Foo" }
- ]
-}})";
-
- Expected<TBDFile> Result =
- TextAPIReader::get(MemoryBufferRef(TBDv5File, "Test.tbd"));
- EXPECT_FALSE(!!Result);
- std::string ErrorMessage = toString(Result.takeError());
- EXPECT_EQ("invalid tapi_tbd_version section\n", ErrorMessage);
-}
-
-TEST(TBDv5, MissingRequiredKey) {
- static const char TBDv5File[] = R"({
-"main_library": {
- "target_info": [
- {
- "target": "arm64-ios-simulator",
- "min_deployment": "11.0"
- }
- ],
- "install_names":[
- { "name":"/S/L/F/Foo.framework/Foo" }
- ]
-}})";
-
- Expected<TBDFile> Result =
- TextAPIReader::get(MemoryBufferRef(TBDv5File, "Test.tbd"));
- EXPECT_FALSE(!!Result);
- std::string ErrorMessage = toString(Result.takeError());
- EXPECT_EQ("invalid tapi_tbd_version section\n", ErrorMessage);
-}
-
-TEST(TBDv5, InvalidSymbols) {
- static const char TBDv5File[] = R"({
-"tapi_tbd_version": 5,
-"main_library": {
- "target_info": [
- {
- "target": "arm64-driverkit",
- "min_deployment": "11.0"
- }
- ],
- "install_names":[
- { "name":"/S/L/F/Foo.framework/Foo" }
- ],
- "exported_symbols": [
- {
- "daa": {
- "global": {
- "weak": []
- }
- }
- }
- ]
-}})";
-
- Expected<TBDFile> Result =
- TextAPIReader::get(MemoryBufferRef(TBDv5File, "Test.tbd"));
- EXPECT_FALSE(!!Result);
- std::string ErrorMessage = toString(Result.takeError());
- EXPECT_EQ("invalid exported_symbols section\n", ErrorMessage);
-}
-
} // end namespace TBDv5