Bug 34563 - NSUrl.FromFilename throws null ref exception if file at path does not exist
Summary: NSUrl.FromFilename throws null ref exception if file at path does not exist
Status: RESOLVED ANSWERED
Alias: None
Product: Xamarin.Mac
Classification: Desktop
Component: Runtime ()
Version: 2.4.0 (C6)
Hardware: Macintosh Mac OS
: --- normal
Target Milestone: ---
Assignee: Chris Hamons
URL:
Depends on:
Blocks:
 
Reported: 2015-10-05 12:35 UTC by Michael Teper
Modified: 2015-10-05 16:19 UTC (History)
2 users (show)

Tags:
Is this bug a regression?: ---
Last known good build:

Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.


Please create a new report on Developer Community or GitHub with your current version information, steps to reproduce, and relevant error messages or log files if you are hitting an issue that looks similar to this resolved bug and you do not yet see a matching new report.

Related Links:
Status:
RESOLVED ANSWERED

Description Michael Teper 2015-10-05 12:35:43 UTC
Simple test:

		[Test]
		public void WhenPathIsValid_ThenNSUrlFromFilenameShouldNotThrow()
		{
			var test = NSUrl.FromFilename("Dummy.name");
			Assert.IsNotNull(test);
		}
Comment 2 Michael Teper 2015-10-05 12:45:06 UTC
Hmm, actually it's failing even if the file exists.

Here's my XS info:

=== Xamarin Studio ===

Version 5.10 (build 800)
Installation UUID: ed6755aa-af00-4433-85c5-a4c5d023bc00
Runtime:
	Mono 4.2.1 (explicit/4a18c57)
	GTK+ 2.24.23 (Raleigh theme)

	Package version: 402010056

=== Xamarin.Profiler ===

Not Installed

=== Apple Developer Tools ===

Xcode 7.0.1 (8228)
Build 7A1001

=== Xamarin.iOS ===

Not Installed

=== Xamarin.Mac ===

Version: 2.4.0.79 (Business Edition)

=== Xamarin.Android ===

Not Installed

=== Xamarin Android Player ===

Not Installed

=== Build Information ===

Release ID: 510000800
Git revision: 92083188182e8c4588153e0d63e99c1a7037e4b6
Build date: 2015-09-18 15:03:06-04
Xamarin addins: 97a862a9dcaa31e9044c8613ef42e0a588c8d012
Build lane: monodevelop-lion-cycle6

=== Operating System ===

Mac OS X 10.11.0
Darwin myellocos-Air 15.0.0 Darwin Kernel Version 15.0.0
    Wed Aug 26 16:57:32 PDT 2015
    root:xnu-3247.1.106~1/RELEASE_X86_64 x86_64
Comment 3 Chris Hamons 2015-10-05 14:18:37 UTC
I am not seeing this when I run from the latest alpha.

However, if I incorrectly try to use NSUrl _before_ NSApplication.Init () I see this. Are you trying to use Cocoa classes before setting up Cocoa globals?
Comment 4 Michael Teper 2015-10-05 14:45:23 UTC
Oh, quite possibly yes, in a unit test! Would it be possible to throw a better exception (e.g. "please make sure to initialize the app first, dummy!")

To make sure though, I updated my unit test to the following:

		[Test]
		public void WhenPathIsValid_ThenNSUrlFromFilenameShouldNotThrow()
		{
			NSApplication.Init();
			
			var test = NSUrl.FromFilename("Dummy.name");
			Assert.IsNotNull(test);
		}

I get a different exception now (running the test in XS):

ObjCRuntime.RuntimeException : Native type size mismatch between Xamarin.Mac.dll and the executing architecture. Xamarin.Mac.dll was built for 64-bit, while the current process is 32-bit.

There is nothing in my project options that suggests 32-bits (or 64-bits for that matter).
Comment 5 Chris Hamons 2015-10-05 15:45:09 UTC
The problem is that we can't easily throw that exception without having every single API that uses cocoa globals (almost everyone) do a boolean if check before invoking into Cocoa. This is too expensive performance wise (last time we checked).

Now on unit testing, the following forum post may be of interest:

http://forums.xamarin.com/discussion/comment/124945/#Comment_124945

With those notes, there were enough people who still really wanted to write unit tests that at least uses non-ui bits of Cocoa. I hacked up a sample here:

https://forums.xamarin.com/discussion/comment/139963/#Comment_139963

that may be useful.

In either case, feel free to open a thread on the forum to discuss the pros/cons of unit testing with XM and any issues you run into. I'm going to close this bug, since this error was only due to incorrect setup.
Comment 6 Michael Teper 2015-10-05 15:56:49 UTC
Chris, I don't think your assessment is entirely valid.

To give broader context, what we are looking to test is a bit of platform specific functionality that isn't tied to UI or (I think) to message pumping and that should, at least in theory, work without grand setup work.

OSX has the concept of file bookmarks that other platforms lack, so we abstracted this function into an interface and the purpose of these series of unit tests is to test this OSX specific implementation. Is it really so wrong to expect to be able to play with NSUrl methods without all the UI scaffolding?

https://developer.apple.com/library/mac/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/AccessingFilesandDirectories/AccessingFilesandDirectories.html#//apple_ref/doc/uid/TP40010672-CH3-SW10
Comment 7 Chris Hamons 2015-10-05 16:19:12 UTC
Michael,

I agree, that in theory, use of NSUrl and friends shouldn't require spinning up the entire world. And it appears, that if you just use that API and no others in Xcode, you can get away with that in objective-c. 

However, as you found out and one of my links mentions, there is a significant amount of setup needed to get the C# -> Objective-C bridge setup (ignore NSApplication globals and UI thread and such for a minute).

You have to have libxammac.a linked it, mono launched correctly, make sure it is the right mono / class lib, etc, etc. We ran into all of these issues ourselves. We have auto tests that invoke Xamarin.Mac APIs that don't require a message pump internally.

All of this mess is all transparent to you when you build a "real" app, since msbuild will invoke mmp for you, which packages everything up for you and generates a nice launcher.

The second link, that builds a test assembly, invokes mmp to package it up, and then invokes guiunit to run it, satisfies all of these by having everyone know all of the state needed.

So, a tl;dr; of above is that anything that uses Xamarin.Mac (Unified) needs a certain amount of care and feeding to get everything setup correctly. If you invoke mmp / use guiunit you get that taken care of. Setting it all up to use a stupid NSUrl is painful, but somebody has to do it, or we can't talk to objective-c for you.