2017-11-14 21:40:11 +03:00
/ *
* Shared unit tests between XI and XM .
* * /
using System ;
2019-02-06 12:27:55 +03:00
using System.Collections.Generic ;
2017-11-14 21:40:11 +03:00
using System.IO ;
2019-02-06 12:27:55 +03:00
using System.Linq ;
2017-11-24 18:52:58 +03:00
using System.Xml ;
2017-11-28 18:43:27 +03:00
using System.Text ;
2017-11-14 21:40:11 +03:00
using NUnit.Framework ;
2019-02-06 12:27:55 +03:00
using Xamarin ;
2017-11-14 21:40:11 +03:00
namespace Xamarin.Tests
{
[TestFixture]
public class ProductTests
{
[Test]
public void MonoVersion ( )
{
// Verify that the mono version is in the Versions.plist, and that it's a parsable version number.
2017-11-24 18:52:58 +03:00
var settings = new XmlReaderSettings ( ) {
XmlResolver = null ,
DtdProcessing = DtdProcessing . Parse
} ;
2017-11-14 21:40:11 +03:00
var plist = Path . Combine ( Configuration . SdkRoot , "Versions.plist" ) ;
2017-11-24 18:52:58 +03:00
var xml = new XmlDocument ( ) ;
2017-11-28 18:43:27 +03:00
using ( var sr = new StreamReader ( plist , Encoding . UTF8 , true ) )
2017-11-24 18:52:58 +03:00
using ( var reader = XmlReader . Create ( sr , settings ) ) {
xml . Load ( reader ) ;
var version = xml . SelectSingleNode ( "//dict/key[text()='MonoVersion']" ) ? . NextSibling ? . InnerText ;
Assert . DoesNotThrow ( ( ) = > Version . Parse ( version ) , "version" ) ;
}
2017-11-14 21:40:11 +03:00
}
2019-02-06 12:27:55 +03:00
[Test]
2019-03-01 10:00:53 +03:00
[TestCase (Profile.macOSSystem, MachO.LoadCommands.MinMacOSX, MachO.Platform.MacOS)]
[TestCase (Profile.macOSFull, MachO.LoadCommands.MinMacOSX, MachO.Platform.MacOS)]
[TestCase (Profile.macOSMobile, MachO.LoadCommands.MinMacOSX, MachO.Platform.MacOS)]
[TestCase (Profile.iOS, MachO.LoadCommands.MiniPhoneOS, MachO.Platform.IOSSimulator, false)]
[TestCase (Profile.iOS, MachO.LoadCommands.MiniPhoneOS, MachO.Platform.IOS, true)]
[TestCase (Profile.watchOS, MachO.LoadCommands.MinwatchOS, MachO.Platform.WatchOSSimulator, false)]
[TestCase (Profile.watchOS, MachO.LoadCommands.MinwatchOS, MachO.Platform.WatchOS, true)]
[TestCase (Profile.tvOS, MachO.LoadCommands.MintvOS, MachO.Platform.TvOSSimulator, false)]
[TestCase (Profile.tvOS, MachO.LoadCommands.MintvOS, MachO.Platform.TvOS, true)]
2019-02-13 05:18:37 +03:00
public void MinOSVersion ( Profile profile , MachO . LoadCommands load_command , MachO . Platform platform , bool device = false )
2019-02-06 12:27:55 +03:00
{
2019-02-06 17:24:08 +03:00
if ( device )
2019-02-07 10:32:59 +03:00
Configuration . AssertDeviceAvailable ( ) ;
2019-02-06 17:24:08 +03:00
2019-03-01 10:00:53 +03:00
var machoFiles = Directory . GetFiles ( Configuration . GetSdkPath ( profile , device ) , "*" , SearchOption . AllDirectories )
. Where ( ( v ) = > {
if ( v . Contains ( "dylib.dSYM/Contents/Resources/DWARF" ) ) {
// Don't include *.dylib from inside .dSYMs.
return false ;
} else if ( v . Contains ( "libxammac-classic" ) | | v . Contains ( "libxammac-system-classic" ) ) {
// We don't care about XM Classic, those are binary dependencies.
return false ;
}
var ext = Path . GetExtension ( v ) ;
return ext = = ".a" | | ext = = ".dylib" ;
}
) ;
2019-02-06 12:27:55 +03:00
var failed = new List < string > ( ) ;
2019-03-01 10:00:53 +03:00
foreach ( var machoFile in machoFiles ) {
var fatfile = MachO . Read ( machoFile ) ;
2019-02-06 12:27:55 +03:00
foreach ( var slice in fatfile ) {
var any_load_command = false ;
foreach ( var lc in slice . load_commands ) {
2019-02-13 05:18:37 +03:00
Version lc_min_version ;
2019-02-06 12:27:55 +03:00
var mincmd = lc as MinCommand ;
2019-02-13 05:18:37 +03:00
if ( mincmd ! = null ) {
Assert . AreEqual ( load_command , mincmd . Command , "Unexpected min load command" ) ;
lc_min_version = mincmd . Version ;
} else {
// starting from iOS SDK 12 the LC_BUILD_VERSION is used instead
var buildver = lc as BuildVersionCommand ;
if ( buildver = = null )
continue ;
2019-02-06 12:27:55 +03:00
2019-03-01 10:02:37 +03:00
var alternativePlatform = ( MachO . Platform ) 0 ;
switch ( platform ) {
case MachO . Platform . IOSSimulator :
alternativePlatform = MachO . Platform . IOS ;
break ;
case MachO . Platform . TvOSSimulator :
alternativePlatform = MachO . Platform . TvOS ;
break ;
case MachO . Platform . WatchOSSimulator :
alternativePlatform = MachO . Platform . WatchOS ;
break ;
}
Assert . That ( buildver . Platform , Is . EqualTo ( platform ) . Or . EqualTo ( alternativePlatform ) , $"Unexpected build version command in {machoFile} ({slice.Filename})" ) ;
2019-02-13 05:18:37 +03:00
lc_min_version = buildver . MinOS ;
}
2019-02-06 12:27:55 +03:00
Version version ;
Version alternate_version = null ;
2019-02-13 05:18:37 +03:00
Version mono_native_compat_version ;
Version mono_native_unified_version ;
2019-05-10 09:22:11 +03:00
Version alternate_mono_native_unified_version = null ;
2019-02-06 12:27:55 +03:00
switch ( load_command ) {
case MachO . LoadCommands . MinMacOSX :
version = SdkVersions . MinOSXVersion ;
2019-02-13 05:18:37 +03:00
mono_native_compat_version = SdkVersions . MinOSXVersion ;
mono_native_unified_version = new Version ( 10 , 12 , 0 ) ;
2019-02-06 12:27:55 +03:00
break ;
case MachO . LoadCommands . MiniPhoneOS :
version = SdkVersions . MiniOSVersion ;
2019-03-01 10:00:53 +03:00
if ( slice . IsDynamicLibrary & & device ) {
2019-02-06 12:27:55 +03:00
if ( version . Major < 7 )
version = new Version ( 7 , 0 , 0 ) ; // dylibs are supported starting with iOS 7.
alternate_version = new Version ( 8 , 0 , 0 ) ; // some iOS dylibs also have min OS 8.0 (if they're used as frameworks as well).
2019-03-01 10:00:53 +03:00
} else if ( slice . Architecture = = MachO . Architectures . ARM64 ) {
alternate_version = new Version ( 7 , 0 , 0 ) ; // our arm64 slices has min iOS 7.0.
2019-02-06 12:27:55 +03:00
}
2019-02-13 05:18:37 +03:00
mono_native_compat_version = SdkVersions . MiniOSVersion ;
mono_native_unified_version = new Version ( 10 , 0 , 0 ) ;
2019-02-06 12:27:55 +03:00
break ;
case MachO . LoadCommands . MintvOS :
version = SdkVersions . MinTVOSVersion ;
2019-02-13 05:18:37 +03:00
mono_native_compat_version = SdkVersions . MinTVOSVersion ;
mono_native_unified_version = new Version ( 10 , 0 , 0 ) ;
2019-02-06 12:27:55 +03:00
break ;
case MachO . LoadCommands . MinwatchOS :
version = SdkVersions . MinWatchOSVersion ;
2019-02-26 19:49:09 +03:00
if ( device )
alternate_version = new Version ( 5 , 1 , 0 ) ; // arm64_32 has min OS 5.1
2019-02-13 05:18:37 +03:00
mono_native_compat_version = SdkVersions . MinWatchOSVersion ;
mono_native_unified_version = new Version ( 5 , 0 , 0 ) ;
2019-05-10 09:22:11 +03:00
if ( device )
alternate_mono_native_unified_version = new Version ( 5 , 1 , 0 ) ; // armv7k has 5.0, arm64_32 has 5.1
2019-02-06 12:27:55 +03:00
break ;
default :
throw new NotImplementedException ( load_command . ToString ( ) ) ;
}
2019-02-13 05:18:37 +03:00
version = version . WithBuild ( ) ;
mono_native_compat_version = mono_native_compat_version . WithBuild ( ) ;
mono_native_unified_version = mono_native_unified_version . WithBuild ( ) ;
2019-02-06 12:27:55 +03:00
if ( alternate_version = = null )
alternate_version = version ;
2019-05-10 09:22:11 +03:00
if ( alternate_mono_native_unified_version = = null )
alternate_mono_native_unified_version = mono_native_unified_version ;
2019-02-06 12:27:55 +03:00
2019-03-01 10:02:37 +03:00
switch ( Path . GetFileName ( machoFile ) ) {
2019-02-13 05:18:37 +03:00
case "libmono-native-compat.dylib" :
2019-03-01 10:02:37 +03:00
case "libmono-native-compat.a" :
2019-02-13 05:18:37 +03:00
if ( mono_native_compat_version ! = lc_min_version )
2019-03-01 10:02:37 +03:00
failed . Add ( $"Unexpected minOS version (expected {mono_native_compat_version}, found {lc_min_version}) in {machoFile} ({slice.Filename})." ) ;
2019-02-13 05:18:37 +03:00
break ;
case "libmono-native-unified.dylib" :
2019-03-01 10:02:37 +03:00
case "libmono-native-unified.a" :
2019-05-10 09:22:11 +03:00
if ( mono_native_unified_version ! = lc_min_version & & alternate_mono_native_unified_version ! = lc_min_version )
2019-03-01 10:02:37 +03:00
failed . Add ( $"Unexpected minOS version (expected {mono_native_unified_version}, found {lc_min_version}) in {machoFile} ({slice.Filename})." ) ;
2019-02-13 05:18:37 +03:00
break ;
default :
if ( version ! = lc_min_version & & alternate_version ! = lc_min_version )
2019-03-01 10:02:37 +03:00
failed . Add ( $"Unexpected minOS version (expected {version}, alternatively {alternate_version}, found {lc_min_version}) in {machoFile} ({slice.Filename})." ) ;
2019-02-13 05:18:37 +03:00
break ;
}
2019-02-06 12:27:55 +03:00
any_load_command = true ;
}
if ( ! any_load_command )
2019-03-01 10:00:53 +03:00
failed . Add ( $"No minOS version found in {machoFile}." ) ;
2019-02-06 12:27:55 +03:00
}
}
CollectionAssert . IsEmpty ( failed , "Failures" ) ;
}
2017-11-14 21:40:11 +03:00
}
2019-02-13 05:18:37 +03:00
static class VersionExtensions
{
public static Version WithBuild ( this Version version )
{
return new Version ( version . Major , version . Minor , version . Build < 0 ? 0 : version . Build ) ;
}
}
2017-11-14 21:40:11 +03:00
}