summaryrefslogtreecommitdiffstats
path: root/xpcom/tests/unit
diff options
context:
space:
mode:
Diffstat (limited to 'xpcom/tests/unit')
-rw-r--r--xpcom/tests/unit/data/SmallApp.app/Contents/Info.plist26
-rwxr-xr-xxpcom/tests/unit/data/SmallApp.app/Contents/MacOS/SmallAppbin0 -> 37988 bytes
-rw-r--r--xpcom/tests/unit/data/SmallApp.app/Contents/PkgInfo1
-rw-r--r--xpcom/tests/unit/data/SmallApp.app/Contents/Resources/English.lproj/InfoPlist.stringsbin0 -> 92 bytes
-rw-r--r--xpcom/tests/unit/data/SmallApp.app/Contents/Resources/English.lproj/MainMenu.nib/designable.nib343
-rw-r--r--xpcom/tests/unit/data/SmallApp.app/Contents/Resources/English.lproj/MainMenu.nib/keyedobjects.nibbin0 -> 3356 bytes
-rw-r--r--xpcom/tests/unit/data/bug121341-2.properties9
-rw-r--r--xpcom/tests/unit/data/bug121341.properties68
-rw-r--r--xpcom/tests/unit/data/iniparser01-utf16leBOM.ini1
-rw-r--r--xpcom/tests/unit/data/iniparser01-utf8BOM.ini1
-rw-r--r--xpcom/tests/unit/data/iniparser01.ini0
-rw-r--r--xpcom/tests/unit/data/iniparser02-utf16leBOM.inibin0 -> 6 bytes
-rw-r--r--xpcom/tests/unit/data/iniparser02-utf8BOM.ini1
-rw-r--r--xpcom/tests/unit/data/iniparser02.ini1
-rw-r--r--xpcom/tests/unit/data/iniparser03-utf16leBOM.inibin0 -> 10 bytes
-rw-r--r--xpcom/tests/unit/data/iniparser03-utf8BOM.ini1
-rw-r--r--xpcom/tests/unit/data/iniparser03.ini1
-rw-r--r--xpcom/tests/unit/data/iniparser04-utf16leBOM.inibin0 -> 26 bytes
-rw-r--r--xpcom/tests/unit/data/iniparser04-utf8BOM.ini1
-rw-r--r--xpcom/tests/unit/data/iniparser04.ini1
-rw-r--r--xpcom/tests/unit/data/iniparser05-utf16leBOM.inibin0 -> 34 bytes
-rw-r--r--xpcom/tests/unit/data/iniparser05-utf8BOM.ini1
-rw-r--r--xpcom/tests/unit/data/iniparser05.ini1
-rw-r--r--xpcom/tests/unit/data/iniparser06-utf16leBOM.inibin0 -> 30 bytes
-rw-r--r--xpcom/tests/unit/data/iniparser06-utf8BOM.ini2
-rw-r--r--xpcom/tests/unit/data/iniparser06.ini2
-rw-r--r--xpcom/tests/unit/data/iniparser07-utf16leBOM.inibin0 -> 40 bytes
-rw-r--r--xpcom/tests/unit/data/iniparser07-utf8BOM.ini2
-rw-r--r--xpcom/tests/unit/data/iniparser07.ini2
-rw-r--r--xpcom/tests/unit/data/iniparser08-utf16leBOM.inibin0 -> 42 bytes
-rw-r--r--xpcom/tests/unit/data/iniparser08-utf8BOM.ini2
-rw-r--r--xpcom/tests/unit/data/iniparser08.ini2
-rw-r--r--xpcom/tests/unit/data/iniparser09-utf16leBOM.inibin0 -> 54 bytes
-rw-r--r--xpcom/tests/unit/data/iniparser09-utf8BOM.ini2
-rw-r--r--xpcom/tests/unit/data/iniparser09.ini2
-rw-r--r--xpcom/tests/unit/data/iniparser10-utf16leBOM.inibin0 -> 58 bytes
-rw-r--r--xpcom/tests/unit/data/iniparser10-utf8BOM.ini3
-rw-r--r--xpcom/tests/unit/data/iniparser10.ini3
-rw-r--r--xpcom/tests/unit/data/iniparser11-utf16leBOM.inibin0 -> 76 bytes
-rw-r--r--xpcom/tests/unit/data/iniparser11-utf8BOM.ini3
-rw-r--r--xpcom/tests/unit/data/iniparser11.ini3
-rw-r--r--xpcom/tests/unit/data/iniparser12-utf16leBOM.inibin0 -> 86 bytes
-rw-r--r--xpcom/tests/unit/data/iniparser12-utf8BOM.ini3
-rw-r--r--xpcom/tests/unit/data/iniparser12.ini3
-rw-r--r--xpcom/tests/unit/data/iniparser13-utf16leBOM.inibin0 -> 94 bytes
-rw-r--r--xpcom/tests/unit/data/iniparser13-utf8BOM.ini3
-rw-r--r--xpcom/tests/unit/data/iniparser13.ini3
-rw-r--r--xpcom/tests/unit/data/iniparser14-utf16leBOM.inibin0 -> 160 bytes
-rw-r--r--xpcom/tests/unit/data/iniparser14-utf8BOM.ini6
-rw-r--r--xpcom/tests/unit/data/iniparser14.ini6
-rw-r--r--xpcom/tests/unit/data/iniparser15-utf16leBOM.inibin0 -> 162 bytes
-rw-r--r--xpcom/tests/unit/data/iniparser15-utf8BOM.ini6
-rw-r--r--xpcom/tests/unit/data/iniparser15.ini6
-rw-r--r--xpcom/tests/unit/data/iniparser16-utf16leBOM.inibin0 -> 210 bytes
-rw-r--r--xpcom/tests/unit/data/iniparser16-utf8BOM.ini13
-rw-r--r--xpcom/tests/unit/data/iniparser16.ini13
-rw-r--r--xpcom/tests/unit/data/iniparser17.ini7
-rw-r--r--xpcom/tests/unit/data/presentation.key/.typeAttributes.dict0
-rw-r--r--xpcom/tests/unit/data/presentation.key/Contents/PkgInfo1
-rw-r--r--xpcom/tests/unit/data/presentation.key/index.apxl.gzbin0 -> 83487 bytes
-rw-r--r--xpcom/tests/unit/data/presentation.key/thumbs/st0.tiffbin0 -> 16654 bytes
-rw-r--r--xpcom/tests/unit/data/process_directive.manifest2
-rw-r--r--xpcom/tests/unit/head_xpcom.js21
-rw-r--r--xpcom/tests/unit/test_bug121341.js62
-rw-r--r--xpcom/tests/unit/test_bug1434856.js27
-rw-r--r--xpcom/tests/unit/test_bug325418.js72
-rw-r--r--xpcom/tests/unit/test_bug332389.js14
-rw-r--r--xpcom/tests/unit/test_bug333505.js10
-rw-r--r--xpcom/tests/unit/test_bug364285-1.js43
-rw-r--r--xpcom/tests/unit/test_bug374754.js65
-rw-r--r--xpcom/tests/unit/test_bug476919.js25
-rw-r--r--xpcom/tests/unit/test_bug478086.js23
-rw-r--r--xpcom/tests/unit/test_bug745466.js7
-rw-r--r--xpcom/tests/unit/test_debugger_malloc_size_of.js32
-rw-r--r--xpcom/tests/unit/test_file_createUnique.js29
-rw-r--r--xpcom/tests/unit/test_file_equality.js37
-rw-r--r--xpcom/tests/unit/test_file_renameTo.js55
-rw-r--r--xpcom/tests/unit/test_hidden_files.js24
-rw-r--r--xpcom/tests/unit/test_home.js18
-rw-r--r--xpcom/tests/unit/test_iniParser.js476
-rw-r--r--xpcom/tests/unit/test_ioutil.js29
-rw-r--r--xpcom/tests/unit/test_localfile.js288
-rw-r--r--xpcom/tests/unit/test_mac_bundle.js18
-rw-r--r--xpcom/tests/unit/test_mac_xattrs.js98
-rw-r--r--xpcom/tests/unit/test_notxpcom_scriptable.js67
-rw-r--r--xpcom/tests/unit/test_nsIMutableArray.js131
-rw-r--r--xpcom/tests/unit/test_nsIProcess.js184
-rw-r--r--xpcom/tests/unit/test_nsIProcess_stress.js24
-rw-r--r--xpcom/tests/unit/test_pipe.js55
-rw-r--r--xpcom/tests/unit/test_process_directives.js20
-rw-r--r--xpcom/tests/unit/test_process_directives_child.js3
-rw-r--r--xpcom/tests/unit/test_seek_multiplex.js164
-rw-r--r--xpcom/tests/unit/test_storagestream.js152
-rw-r--r--xpcom/tests/unit/test_streams.js170
-rw-r--r--xpcom/tests/unit/test_stringstream.js20
-rw-r--r--xpcom/tests/unit/test_symlinks.js142
-rw-r--r--xpcom/tests/unit/test_systemInfo.js26
-rw-r--r--xpcom/tests/unit/test_versioncomparator.js55
-rw-r--r--xpcom/tests/unit/test_windows_cmdline_file.js22
-rw-r--r--xpcom/tests/unit/test_windows_registry.js237
-rw-r--r--xpcom/tests/unit/xpcshell.ini66
101 files changed, 3568 insertions, 0 deletions
diff --git a/xpcom/tests/unit/data/SmallApp.app/Contents/Info.plist b/xpcom/tests/unit/data/SmallApp.app/Contents/Info.plist
new file mode 100644
index 0000000000..8388fa2a55
--- /dev/null
+++ b/xpcom/tests/unit/data/SmallApp.app/Contents/Info.plist
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleExecutable</key>
+ <string>SmallApp</string>
+ <key>CFBundleIdentifier</key>
+ <string>com.yourcompany.SmallApp</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>SmallApp</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1.0</string>
+ <key>NSMainNibFile</key>
+ <string>MainMenu</string>
+ <key>NSPrincipalClass</key>
+ <string>NSApplication</string>
+</dict>
+</plist>
diff --git a/xpcom/tests/unit/data/SmallApp.app/Contents/MacOS/SmallApp b/xpcom/tests/unit/data/SmallApp.app/Contents/MacOS/SmallApp
new file mode 100755
index 0000000000..c821003d34
--- /dev/null
+++ b/xpcom/tests/unit/data/SmallApp.app/Contents/MacOS/SmallApp
Binary files differ
diff --git a/xpcom/tests/unit/data/SmallApp.app/Contents/PkgInfo b/xpcom/tests/unit/data/SmallApp.app/Contents/PkgInfo
new file mode 100644
index 0000000000..bd04210fb4
--- /dev/null
+++ b/xpcom/tests/unit/data/SmallApp.app/Contents/PkgInfo
@@ -0,0 +1 @@
+APPL???? \ No newline at end of file
diff --git a/xpcom/tests/unit/data/SmallApp.app/Contents/Resources/English.lproj/InfoPlist.strings b/xpcom/tests/unit/data/SmallApp.app/Contents/Resources/English.lproj/InfoPlist.strings
new file mode 100644
index 0000000000..5e45963c38
--- /dev/null
+++ b/xpcom/tests/unit/data/SmallApp.app/Contents/Resources/English.lproj/InfoPlist.strings
Binary files differ
diff --git a/xpcom/tests/unit/data/SmallApp.app/Contents/Resources/English.lproj/MainMenu.nib/designable.nib b/xpcom/tests/unit/data/SmallApp.app/Contents/Resources/English.lproj/MainMenu.nib/designable.nib
new file mode 100644
index 0000000000..59f8803c5d
--- /dev/null
+++ b/xpcom/tests/unit/data/SmallApp.app/Contents/Resources/English.lproj/MainMenu.nib/designable.nib
@@ -0,0 +1,343 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.02">
+ <data>
+ <int key="IBDocument.SystemTarget">0</int>
+ <string key="IBDocument.SystemVersion">9E17</string>
+ <string key="IBDocument.InterfaceBuilderVersion">644</string>
+ <string key="IBDocument.AppKitVersion">949.33</string>
+ <string key="IBDocument.HIToolboxVersion">352.00</string>
+ <object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <integer value="29"/>
+ </object>
+ <object class="NSArray" key="IBDocument.PluginDependencies">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>com.apple.InterfaceBuilderKit</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ </object>
+ <object class="NSMutableArray" key="IBDocument.RootObjects" id="1048">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSCustomObject" id="1021">
+ <string key="NSClassName">NSApplication</string>
+ </object>
+ <object class="NSCustomObject" id="1014">
+ <string key="NSClassName">FirstResponder</string>
+ </object>
+ <object class="NSCustomObject" id="1050">
+ <string key="NSClassName">NSApplication</string>
+ </object>
+ <object class="NSMenu" id="649796088">
+ <string key="NSTitle">AMainMenu</string>
+ <object class="NSMutableArray" key="NSMenuItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMenuItem" id="694149608">
+ <reference key="NSMenu" ref="649796088"/>
+ <string key="NSTitle">NewApplication</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <object class="NSCustomResource" key="NSOnImage" id="35465992">
+ <string key="NSClassName">NSImage</string>
+ <string key="NSResourceName">NSMenuCheckmark</string>
+ </object>
+ <object class="NSCustomResource" key="NSMixedImage" id="591987212">
+ <string key="NSClassName">NSImage</string>
+ <string key="NSResourceName">NSMenuMixedState</string>
+ </object>
+ <string key="NSAction">submenuAction:</string>
+ <object class="NSMenu" key="NSSubmenu" id="110575045">
+ <string key="NSTitle">NewApplication</string>
+ <object class="NSMutableArray" key="NSMenuItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMenuItem" id="632727374">
+ <reference key="NSMenu" ref="110575045"/>
+ <string key="NSTitle">Quit NewApplication</string>
+ <string key="NSKeyEquiv">q</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="591987212"/>
+ </object>
+ </object>
+ <string key="NSName">_NSAppleMenu</string>
+ </object>
+ </object>
+ <object class="NSMenuItem" id="379814623">
+ <reference key="NSMenu" ref="649796088"/>
+ <string key="NSTitle">File</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="591987212"/>
+ </object>
+ <object class="NSMenuItem" id="952259628">
+ <reference key="NSMenu" ref="649796088"/>
+ <string key="NSTitle">Edit</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="591987212"/>
+ </object>
+ <object class="NSMenuItem" id="626404410">
+ <reference key="NSMenu" ref="649796088"/>
+ <string key="NSTitle">Format</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="591987212"/>
+ </object>
+ <object class="NSMenuItem" id="586577488">
+ <reference key="NSMenu" ref="649796088"/>
+ <string key="NSTitle">View</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="591987212"/>
+ </object>
+ <object class="NSMenuItem" id="713487014">
+ <reference key="NSMenu" ref="649796088"/>
+ <string key="NSTitle">Window</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="591987212"/>
+ </object>
+ <object class="NSMenuItem" id="391199113">
+ <reference key="NSMenu" ref="649796088"/>
+ <string key="NSTitle">Help</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="591987212"/>
+ </object>
+ </object>
+ <string key="NSName">_NSMainMenu</string>
+ </object>
+ </object>
+ <object class="IBObjectContainer" key="IBDocument.Objects">
+ <object class="NSMutableArray" key="connectionRecords">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">terminate:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="632727374"/>
+ </object>
+ <int key="connectionID">369</int>
+ </object>
+ </object>
+ <object class="IBMutableOrderedSet" key="objectRecords">
+ <object class="NSArray" key="orderedObjects">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBObjectRecord">
+ <int key="objectID">0</int>
+ <object class="NSArray" key="object" id="1049">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ <reference key="children" ref="1048"/>
+ <nil key="parent"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">-2</int>
+ <reference key="object" ref="1021"/>
+ <reference key="parent" ref="1049"/>
+ <string type="base64-UTF8" key="objectName">RmlsZSdzIE93bmVyA</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">-1</int>
+ <reference key="object" ref="1014"/>
+ <reference key="parent" ref="1049"/>
+ <string key="objectName">First Responder</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">-3</int>
+ <reference key="object" ref="1050"/>
+ <reference key="parent" ref="1049"/>
+ <string key="objectName">Application</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">29</int>
+ <reference key="object" ref="649796088"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="713487014"/>
+ <reference ref="694149608"/>
+ <reference ref="391199113"/>
+ <reference ref="952259628"/>
+ <reference ref="379814623"/>
+ <reference ref="586577488"/>
+ <reference ref="626404410"/>
+ </object>
+ <reference key="parent" ref="1049"/>
+ <string key="objectName">MainMenu</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">19</int>
+ <reference key="object" ref="713487014"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ <reference key="parent" ref="649796088"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">56</int>
+ <reference key="object" ref="694149608"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="110575045"/>
+ </object>
+ <reference key="parent" ref="649796088"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">103</int>
+ <reference key="object" ref="391199113"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ <reference key="parent" ref="649796088"/>
+ <string key="objectName">1</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">217</int>
+ <reference key="object" ref="952259628"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ <reference key="parent" ref="649796088"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">83</int>
+ <reference key="object" ref="379814623"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ <reference key="parent" ref="649796088"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">57</int>
+ <reference key="object" ref="110575045"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="632727374"/>
+ </object>
+ <reference key="parent" ref="694149608"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">136</int>
+ <reference key="object" ref="632727374"/>
+ <reference key="parent" ref="110575045"/>
+ <string key="objectName">1111</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">295</int>
+ <reference key="object" ref="586577488"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ <reference key="parent" ref="649796088"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">299</int>
+ <reference key="object" ref="626404410"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ <reference key="parent" ref="649796088"/>
+ </object>
+ </object>
+ </object>
+ <object class="NSMutableDictionary" key="flattenedProperties">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMutableArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>-1.IBPluginDependency</string>
+ <string>-2.IBPluginDependency</string>
+ <string>-3.IBPluginDependency</string>
+ <string>103.IBPluginDependency</string>
+ <string>103.ImportedFromIB2</string>
+ <string>136.IBPluginDependency</string>
+ <string>136.ImportedFromIB2</string>
+ <string>19.IBPluginDependency</string>
+ <string>19.ImportedFromIB2</string>
+ <string>217.IBPluginDependency</string>
+ <string>217.ImportedFromIB2</string>
+ <string>29.IBEditorWindowLastContentRect</string>
+ <string>29.IBPluginDependency</string>
+ <string>29.ImportedFromIB2</string>
+ <string>29.WindowOrigin</string>
+ <string>29.editorWindowContentRectSynchronizationRect</string>
+ <string>295.IBPluginDependency</string>
+ <string>299.IBPluginDependency</string>
+ <string>56.IBPluginDependency</string>
+ <string>56.ImportedFromIB2</string>
+ <string>57.IBEditorWindowLastContentRect</string>
+ <string>57.IBPluginDependency</string>
+ <string>57.ImportedFromIB2</string>
+ <string>57.editorWindowContentRectSynchronizationRect</string>
+ <string>83.IBPluginDependency</string>
+ <string>83.ImportedFromIB2</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilderKit</string>
+ <string>com.apple.InterfaceBuilderKit</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1" id="9"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <reference ref="9"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <reference ref="9"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <reference ref="9"/>
+ <string>{{0, 975}, {478, 20}}</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <reference ref="9"/>
+ <string>{74, 862}</string>
+ <string>{{6, 978}, {478, 20}}</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <reference ref="9"/>
+ <string>{{12, 952}, {218, 23}}</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <reference ref="9"/>
+ <string>{{23, 794}, {245, 183}}</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <reference ref="9"/>
+ </object>
+ </object>
+ <object class="NSMutableDictionary" key="unlocalizedProperties">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ </object>
+ <nil key="activeLocalization"/>
+ <object class="NSMutableDictionary" key="localizations">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ </object>
+ <nil key="sourceID"/>
+ <int key="maxID">374</int>
+ </object>
+ <object class="IBClassDescriber" key="IBDocument.Classes"/>
+ <int key="IBDocument.localizationMode">0</int>
+ <string key="IBDocument.LastKnownRelativeProjectPath">../SmallApp.xcodeproj</string>
+ <int key="IBDocument.defaultPropertyAccessControl">3</int>
+ </data>
+</archive>
diff --git a/xpcom/tests/unit/data/SmallApp.app/Contents/Resources/English.lproj/MainMenu.nib/keyedobjects.nib b/xpcom/tests/unit/data/SmallApp.app/Contents/Resources/English.lproj/MainMenu.nib/keyedobjects.nib
new file mode 100644
index 0000000000..bb27d4a5d6
--- /dev/null
+++ b/xpcom/tests/unit/data/SmallApp.app/Contents/Resources/English.lproj/MainMenu.nib/keyedobjects.nib
Binary files differ
diff --git a/xpcom/tests/unit/data/bug121341-2.properties b/xpcom/tests/unit/data/bug121341-2.properties
new file mode 100644
index 0000000000..f7885e4fca
--- /dev/null
+++ b/xpcom/tests/unit/data/bug121341-2.properties
@@ -0,0 +1,9 @@
+# this file contains invalid UTF-8 sequence
+# no property should be loaded
+
+1 = test
+
+# property with invalid UTF-8 sequence (0xa0)
+2 = a b
+
+3 = test2
diff --git a/xpcom/tests/unit/data/bug121341.properties b/xpcom/tests/unit/data/bug121341.properties
new file mode 100644
index 0000000000..b45fc9698c
--- /dev/null
+++ b/xpcom/tests/unit/data/bug121341.properties
@@ -0,0 +1,68 @@
+# simple check
+1=abc
+# test whitespace trimming in key and value
+ 2 = xy
+# test parsing of escaped values
+3 = \u1234\t\r\n\uAB\
+\u1\n
+# test multiline properties
+4 = this is \
+multiline property
+5 = this is \
+ another multiline property
+# property with DOS EOL
+6 = test\u0036
+# test multiline property with with DOS EOL
+7 = yet another multi\
+ line propery
+# trimming should not trim escaped whitespaces
+8 = \ttest5\u0020
+# another variant of #8
+9 = \ test6\t
+# test UTF-8 encoded property/value
+10aሴb = c췯d
+# next property should test unicode escaping at the boundary of parsing buffer
+# buffer size is expected to be 4096 so add comments to get to this offset
+################################################################################
+################################################################################
+################################################################################
+################################################################################
+################################################################################
+################################################################################
+################################################################################
+################################################################################
+################################################################################
+################################################################################
+################################################################################
+################################################################################
+################################################################################
+################################################################################
+################################################################################
+################################################################################
+################################################################################
+################################################################################
+################################################################################
+################################################################################
+################################################################################
+################################################################################
+################################################################################
+################################################################################
+################################################################################
+################################################################################
+################################################################################
+################################################################################
+################################################################################
+################################################################################
+################################################################################
+################################################################################
+################################################################################
+################################################################################
+################################################################################
+################################################################################
+################################################################################
+################################################################################
+################################################################################
+################################################################################
+################################################################################
+###############################################################################
+11 = \uABCD
diff --git a/xpcom/tests/unit/data/iniparser01-utf16leBOM.ini b/xpcom/tests/unit/data/iniparser01-utf16leBOM.ini
new file mode 100644
index 0000000000..46b134b197
--- /dev/null
+++ b/xpcom/tests/unit/data/iniparser01-utf16leBOM.ini
@@ -0,0 +1 @@
+ÿþ \ No newline at end of file
diff --git a/xpcom/tests/unit/data/iniparser01-utf8BOM.ini b/xpcom/tests/unit/data/iniparser01-utf8BOM.ini
new file mode 100644
index 0000000000..5f282702bb
--- /dev/null
+++ b/xpcom/tests/unit/data/iniparser01-utf8BOM.ini
@@ -0,0 +1 @@
+ \ No newline at end of file
diff --git a/xpcom/tests/unit/data/iniparser01.ini b/xpcom/tests/unit/data/iniparser01.ini
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/xpcom/tests/unit/data/iniparser01.ini
diff --git a/xpcom/tests/unit/data/iniparser02-utf16leBOM.ini b/xpcom/tests/unit/data/iniparser02-utf16leBOM.ini
new file mode 100644
index 0000000000..49cc8ef0e1
--- /dev/null
+++ b/xpcom/tests/unit/data/iniparser02-utf16leBOM.ini
Binary files differ
diff --git a/xpcom/tests/unit/data/iniparser02-utf8BOM.ini b/xpcom/tests/unit/data/iniparser02-utf8BOM.ini
new file mode 100644
index 0000000000..e02abfc9b0
--- /dev/null
+++ b/xpcom/tests/unit/data/iniparser02-utf8BOM.ini
@@ -0,0 +1 @@
+
diff --git a/xpcom/tests/unit/data/iniparser02.ini b/xpcom/tests/unit/data/iniparser02.ini
new file mode 100644
index 0000000000..d3f5a12faa
--- /dev/null
+++ b/xpcom/tests/unit/data/iniparser02.ini
@@ -0,0 +1 @@
+
diff --git a/xpcom/tests/unit/data/iniparser03-utf16leBOM.ini b/xpcom/tests/unit/data/iniparser03-utf16leBOM.ini
new file mode 100644
index 0000000000..05255100a2
--- /dev/null
+++ b/xpcom/tests/unit/data/iniparser03-utf16leBOM.ini
Binary files differ
diff --git a/xpcom/tests/unit/data/iniparser03-utf8BOM.ini b/xpcom/tests/unit/data/iniparser03-utf8BOM.ini
new file mode 100644
index 0000000000..b76e44e194
--- /dev/null
+++ b/xpcom/tests/unit/data/iniparser03-utf8BOM.ini
@@ -0,0 +1 @@
+[]
diff --git a/xpcom/tests/unit/data/iniparser03.ini b/xpcom/tests/unit/data/iniparser03.ini
new file mode 100644
index 0000000000..60b0742537
--- /dev/null
+++ b/xpcom/tests/unit/data/iniparser03.ini
@@ -0,0 +1 @@
+[]
diff --git a/xpcom/tests/unit/data/iniparser04-utf16leBOM.ini b/xpcom/tests/unit/data/iniparser04-utf16leBOM.ini
new file mode 100644
index 0000000000..e95d971134
--- /dev/null
+++ b/xpcom/tests/unit/data/iniparser04-utf16leBOM.ini
Binary files differ
diff --git a/xpcom/tests/unit/data/iniparser04-utf8BOM.ini b/xpcom/tests/unit/data/iniparser04-utf8BOM.ini
new file mode 100644
index 0000000000..47ef32c0a9
--- /dev/null
+++ b/xpcom/tests/unit/data/iniparser04-utf8BOM.ini
@@ -0,0 +1 @@
+[section1]
diff --git a/xpcom/tests/unit/data/iniparser04.ini b/xpcom/tests/unit/data/iniparser04.ini
new file mode 100644
index 0000000000..23a50d155f
--- /dev/null
+++ b/xpcom/tests/unit/data/iniparser04.ini
@@ -0,0 +1 @@
+[section1]
diff --git a/xpcom/tests/unit/data/iniparser05-utf16leBOM.ini b/xpcom/tests/unit/data/iniparser05-utf16leBOM.ini
new file mode 100644
index 0000000000..a49491816c
--- /dev/null
+++ b/xpcom/tests/unit/data/iniparser05-utf16leBOM.ini
Binary files differ
diff --git a/xpcom/tests/unit/data/iniparser05-utf8BOM.ini b/xpcom/tests/unit/data/iniparser05-utf8BOM.ini
new file mode 100644
index 0000000000..eb33b5ccf1
--- /dev/null
+++ b/xpcom/tests/unit/data/iniparser05-utf8BOM.ini
@@ -0,0 +1 @@
+[section1]junk
diff --git a/xpcom/tests/unit/data/iniparser05.ini b/xpcom/tests/unit/data/iniparser05.ini
new file mode 100644
index 0000000000..ade1373377
--- /dev/null
+++ b/xpcom/tests/unit/data/iniparser05.ini
@@ -0,0 +1 @@
+[section1]junk
diff --git a/xpcom/tests/unit/data/iniparser06-utf16leBOM.ini b/xpcom/tests/unit/data/iniparser06-utf16leBOM.ini
new file mode 100644
index 0000000000..e9023ac7c9
--- /dev/null
+++ b/xpcom/tests/unit/data/iniparser06-utf16leBOM.ini
Binary files differ
diff --git a/xpcom/tests/unit/data/iniparser06-utf8BOM.ini b/xpcom/tests/unit/data/iniparser06-utf8BOM.ini
new file mode 100644
index 0000000000..073d841cf3
--- /dev/null
+++ b/xpcom/tests/unit/data/iniparser06-utf8BOM.ini
@@ -0,0 +1,2 @@
+[section1]
+
diff --git a/xpcom/tests/unit/data/iniparser06.ini b/xpcom/tests/unit/data/iniparser06.ini
new file mode 100644
index 0000000000..c24821e6ed
--- /dev/null
+++ b/xpcom/tests/unit/data/iniparser06.ini
@@ -0,0 +1,2 @@
+[section1]
+
diff --git a/xpcom/tests/unit/data/iniparser07-utf16leBOM.ini b/xpcom/tests/unit/data/iniparser07-utf16leBOM.ini
new file mode 100644
index 0000000000..d1c167e6e3
--- /dev/null
+++ b/xpcom/tests/unit/data/iniparser07-utf16leBOM.ini
Binary files differ
diff --git a/xpcom/tests/unit/data/iniparser07-utf8BOM.ini b/xpcom/tests/unit/data/iniparser07-utf8BOM.ini
new file mode 100644
index 0000000000..38176d9444
--- /dev/null
+++ b/xpcom/tests/unit/data/iniparser07-utf8BOM.ini
@@ -0,0 +1,2 @@
+[section1]
+name1
diff --git a/xpcom/tests/unit/data/iniparser07.ini b/xpcom/tests/unit/data/iniparser07.ini
new file mode 100644
index 0000000000..49816873b2
--- /dev/null
+++ b/xpcom/tests/unit/data/iniparser07.ini
@@ -0,0 +1,2 @@
+[section1]
+name1
diff --git a/xpcom/tests/unit/data/iniparser08-utf16leBOM.ini b/xpcom/tests/unit/data/iniparser08-utf16leBOM.ini
new file mode 100644
index 0000000000..e450566a0f
--- /dev/null
+++ b/xpcom/tests/unit/data/iniparser08-utf16leBOM.ini
Binary files differ
diff --git a/xpcom/tests/unit/data/iniparser08-utf8BOM.ini b/xpcom/tests/unit/data/iniparser08-utf8BOM.ini
new file mode 100644
index 0000000000..5fa7d2495c
--- /dev/null
+++ b/xpcom/tests/unit/data/iniparser08-utf8BOM.ini
@@ -0,0 +1,2 @@
+[section1]
+name1=
diff --git a/xpcom/tests/unit/data/iniparser08.ini b/xpcom/tests/unit/data/iniparser08.ini
new file mode 100644
index 0000000000..cfa15c9ffe
--- /dev/null
+++ b/xpcom/tests/unit/data/iniparser08.ini
@@ -0,0 +1,2 @@
+[section1]
+name1=
diff --git a/xpcom/tests/unit/data/iniparser09-utf16leBOM.ini b/xpcom/tests/unit/data/iniparser09-utf16leBOM.ini
new file mode 100644
index 0000000000..ef1da39e27
--- /dev/null
+++ b/xpcom/tests/unit/data/iniparser09-utf16leBOM.ini
Binary files differ
diff --git a/xpcom/tests/unit/data/iniparser09-utf8BOM.ini b/xpcom/tests/unit/data/iniparser09-utf8BOM.ini
new file mode 100644
index 0000000000..e3edce4d49
--- /dev/null
+++ b/xpcom/tests/unit/data/iniparser09-utf8BOM.ini
@@ -0,0 +1,2 @@
+[section1]
+name1=value1
diff --git a/xpcom/tests/unit/data/iniparser09.ini b/xpcom/tests/unit/data/iniparser09.ini
new file mode 100644
index 0000000000..1c87762ba4
--- /dev/null
+++ b/xpcom/tests/unit/data/iniparser09.ini
@@ -0,0 +1,2 @@
+[section1]
+name1=value1
diff --git a/xpcom/tests/unit/data/iniparser10-utf16leBOM.ini b/xpcom/tests/unit/data/iniparser10-utf16leBOM.ini
new file mode 100644
index 0000000000..e5e70b6612
--- /dev/null
+++ b/xpcom/tests/unit/data/iniparser10-utf16leBOM.ini
Binary files differ
diff --git a/xpcom/tests/unit/data/iniparser10-utf8BOM.ini b/xpcom/tests/unit/data/iniparser10-utf8BOM.ini
new file mode 100644
index 0000000000..bda15fcc7b
--- /dev/null
+++ b/xpcom/tests/unit/data/iniparser10-utf8BOM.ini
@@ -0,0 +1,3 @@
+
+[section1]
+name1=value1
diff --git a/xpcom/tests/unit/data/iniparser10.ini b/xpcom/tests/unit/data/iniparser10.ini
new file mode 100644
index 0000000000..037fd79303
--- /dev/null
+++ b/xpcom/tests/unit/data/iniparser10.ini
@@ -0,0 +1,3 @@
+
+[section1]
+name1=value1
diff --git a/xpcom/tests/unit/data/iniparser11-utf16leBOM.ini b/xpcom/tests/unit/data/iniparser11-utf16leBOM.ini
new file mode 100644
index 0000000000..932d4004bc
--- /dev/null
+++ b/xpcom/tests/unit/data/iniparser11-utf16leBOM.ini
Binary files differ
diff --git a/xpcom/tests/unit/data/iniparser11-utf8BOM.ini b/xpcom/tests/unit/data/iniparser11-utf8BOM.ini
new file mode 100644
index 0000000000..78caafaba5
--- /dev/null
+++ b/xpcom/tests/unit/data/iniparser11-utf8BOM.ini
@@ -0,0 +1,3 @@
+# comment
+[section1]
+name1=value1
diff --git a/xpcom/tests/unit/data/iniparser11.ini b/xpcom/tests/unit/data/iniparser11.ini
new file mode 100644
index 0000000000..f8d573a284
--- /dev/null
+++ b/xpcom/tests/unit/data/iniparser11.ini
@@ -0,0 +1,3 @@
+# comment
+[section1]
+name1=value1
diff --git a/xpcom/tests/unit/data/iniparser12-utf16leBOM.ini b/xpcom/tests/unit/data/iniparser12-utf16leBOM.ini
new file mode 100644
index 0000000000..8a29127222
--- /dev/null
+++ b/xpcom/tests/unit/data/iniparser12-utf16leBOM.ini
Binary files differ
diff --git a/xpcom/tests/unit/data/iniparser12-utf8BOM.ini b/xpcom/tests/unit/data/iniparser12-utf8BOM.ini
new file mode 100644
index 0000000000..09ca62779d
--- /dev/null
+++ b/xpcom/tests/unit/data/iniparser12-utf8BOM.ini
@@ -0,0 +1,3 @@
+[section1]
+# [sectionBAD]
+name1=value1
diff --git a/xpcom/tests/unit/data/iniparser12.ini b/xpcom/tests/unit/data/iniparser12.ini
new file mode 100644
index 0000000000..2727940c09
--- /dev/null
+++ b/xpcom/tests/unit/data/iniparser12.ini
@@ -0,0 +1,3 @@
+[section1]
+# [sectionBAD]
+name1=value1
diff --git a/xpcom/tests/unit/data/iniparser13-utf16leBOM.ini b/xpcom/tests/unit/data/iniparser13-utf16leBOM.ini
new file mode 100644
index 0000000000..ebd9a51d3e
--- /dev/null
+++ b/xpcom/tests/unit/data/iniparser13-utf16leBOM.ini
Binary files differ
diff --git a/xpcom/tests/unit/data/iniparser13-utf8BOM.ini b/xpcom/tests/unit/data/iniparser13-utf8BOM.ini
new file mode 100644
index 0000000000..8c9499b669
--- /dev/null
+++ b/xpcom/tests/unit/data/iniparser13-utf8BOM.ini
@@ -0,0 +1,3 @@
+[section1]
+name1=value1
+# nameBAD=valueBAD
diff --git a/xpcom/tests/unit/data/iniparser13.ini b/xpcom/tests/unit/data/iniparser13.ini
new file mode 100644
index 0000000000..21d40b140c
--- /dev/null
+++ b/xpcom/tests/unit/data/iniparser13.ini
@@ -0,0 +1,3 @@
+[section1]
+name1=value1
+# nameBAD=valueBAD
diff --git a/xpcom/tests/unit/data/iniparser14-utf16leBOM.ini b/xpcom/tests/unit/data/iniparser14-utf16leBOM.ini
new file mode 100644
index 0000000000..bbc3413aa1
--- /dev/null
+++ b/xpcom/tests/unit/data/iniparser14-utf16leBOM.ini
Binary files differ
diff --git a/xpcom/tests/unit/data/iniparser14-utf8BOM.ini b/xpcom/tests/unit/data/iniparser14-utf8BOM.ini
new file mode 100644
index 0000000000..d109052c8d
--- /dev/null
+++ b/xpcom/tests/unit/data/iniparser14-utf8BOM.ini
@@ -0,0 +1,6 @@
+[section1]
+name1=value1
+name2=value2
+[section2]
+name1=value1
+name2=foopy
diff --git a/xpcom/tests/unit/data/iniparser14.ini b/xpcom/tests/unit/data/iniparser14.ini
new file mode 100644
index 0000000000..744af4cb65
--- /dev/null
+++ b/xpcom/tests/unit/data/iniparser14.ini
@@ -0,0 +1,6 @@
+[section1]
+name1=value1
+name2=value2
+[section2]
+name1=value1
+name2=foopy
diff --git a/xpcom/tests/unit/data/iniparser15-utf16leBOM.ini b/xpcom/tests/unit/data/iniparser15-utf16leBOM.ini
new file mode 100644
index 0000000000..e60525dec6
--- /dev/null
+++ b/xpcom/tests/unit/data/iniparser15-utf16leBOM.ini
Binary files differ
diff --git a/xpcom/tests/unit/data/iniparser15-utf8BOM.ini b/xpcom/tests/unit/data/iniparser15-utf8BOM.ini
new file mode 100644
index 0000000000..172803f90b
--- /dev/null
+++ b/xpcom/tests/unit/data/iniparser15-utf8BOM.ini
@@ -0,0 +1,6 @@
+[section1]
+name1=value1
+[section2]
+name1=foopy
+[section1]
+name1=newValue1
diff --git a/xpcom/tests/unit/data/iniparser15.ini b/xpcom/tests/unit/data/iniparser15.ini
new file mode 100644
index 0000000000..608a27d8fb
--- /dev/null
+++ b/xpcom/tests/unit/data/iniparser15.ini
@@ -0,0 +1,6 @@
+[section1]
+name1=value1
+[section2]
+name1=foopy
+[section1]
+name1=newValue1
diff --git a/xpcom/tests/unit/data/iniparser16-utf16leBOM.ini b/xpcom/tests/unit/data/iniparser16-utf16leBOM.ini
new file mode 100644
index 0000000000..142b175902
--- /dev/null
+++ b/xpcom/tests/unit/data/iniparser16-utf16leBOM.ini
Binary files differ
diff --git a/xpcom/tests/unit/data/iniparser16-utf8BOM.ini b/xpcom/tests/unit/data/iniparser16-utf8BOM.ini
new file mode 100644
index 0000000000..bba1018dab
--- /dev/null
+++ b/xpcom/tests/unit/data/iniparser16-utf8BOM.ini
@@ -0,0 +1,13 @@
+#á¿»á¹Ò³Ï–·Ì˄ȡǨŅ©&
+[☺♫]
+#ѼΏá¹Ò³Ï–
+♫=☻
+#·Ì˄ȡǨŅ©
+♪=♥
+#‽ἧᵿΏá¹Ò³
+#ϖ·Ì˄ȡǨŅ©&
+[☼]
+♣=♠
+♦=♥
+#‽ἧᵿΏá¹Ò³
+#·Ì˄ȡǨŅ©
diff --git a/xpcom/tests/unit/data/iniparser16.ini b/xpcom/tests/unit/data/iniparser16.ini
new file mode 100644
index 0000000000..b94607d15d
--- /dev/null
+++ b/xpcom/tests/unit/data/iniparser16.ini
@@ -0,0 +1,13 @@
+#á¿»á¹Ò³Ï–·Ì˄ȡǨŅ©&
+[☺♫]
+#ѼΏá¹Ò³Ï–
+♫=☻
+#·Ì˄ȡǨŅ©
+♪=♥
+#‽ἧᵿΏá¹Ò³
+#ϖ·Ì˄ȡǨŅ©&
+[☼]
+♣=♠
+♦=♥
+#‽ἧᵿΏá¹Ò³
+#·Ì˄ȡǨŅ©
diff --git a/xpcom/tests/unit/data/iniparser17.ini b/xpcom/tests/unit/data/iniparser17.ini
new file mode 100644
index 0000000000..bc4815b8c7
--- /dev/null
+++ b/xpcom/tests/unit/data/iniparser17.ini
@@ -0,0 +1,7 @@
+[section]
+key=
+
+[]
+
+[empty]
+=foo
diff --git a/xpcom/tests/unit/data/presentation.key/.typeAttributes.dict b/xpcom/tests/unit/data/presentation.key/.typeAttributes.dict
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/xpcom/tests/unit/data/presentation.key/.typeAttributes.dict
diff --git a/xpcom/tests/unit/data/presentation.key/Contents/PkgInfo b/xpcom/tests/unit/data/presentation.key/Contents/PkgInfo
new file mode 100644
index 0000000000..b0bc8e0761
--- /dev/null
+++ b/xpcom/tests/unit/data/presentation.key/Contents/PkgInfo
@@ -0,0 +1 @@
+???????? \ No newline at end of file
diff --git a/xpcom/tests/unit/data/presentation.key/index.apxl.gz b/xpcom/tests/unit/data/presentation.key/index.apxl.gz
new file mode 100644
index 0000000000..26178d809e
--- /dev/null
+++ b/xpcom/tests/unit/data/presentation.key/index.apxl.gz
Binary files differ
diff --git a/xpcom/tests/unit/data/presentation.key/thumbs/st0.tiff b/xpcom/tests/unit/data/presentation.key/thumbs/st0.tiff
new file mode 100644
index 0000000000..8b49316b4d
--- /dev/null
+++ b/xpcom/tests/unit/data/presentation.key/thumbs/st0.tiff
Binary files differ
diff --git a/xpcom/tests/unit/data/process_directive.manifest b/xpcom/tests/unit/data/process_directive.manifest
new file mode 100644
index 0000000000..3deb2ec444
--- /dev/null
+++ b/xpcom/tests/unit/data/process_directive.manifest
@@ -0,0 +1,2 @@
+category directives-test main-process @mozilla.org/supports-cstring;1 process=main
+category directives-test content-process @mozilla.org/supports-cstring;1 process=content
diff --git a/xpcom/tests/unit/head_xpcom.js b/xpcom/tests/unit/head_xpcom.js
new file mode 100644
index 0000000000..e2ae79cb12
--- /dev/null
+++ b/xpcom/tests/unit/head_xpcom.js
@@ -0,0 +1,21 @@
+let CC = Components.Constructor;
+
+function get_test_program(prog) {
+ var progPath = do_get_cwd();
+ progPath.append(prog);
+ progPath.leafName = progPath.leafName + mozinfo.bin_suffix;
+ return progPath;
+}
+
+function set_process_running_environment() {
+ // Importing Services here messes up appInfo for some of the tests.
+ // eslint-disable-next-line mozilla/use-services
+ var dirSvc = Cc["@mozilla.org/file/directory_service;1"].getService(
+ Ci.nsIProperties
+ );
+ var greBinDir = dirSvc.get("GreBinD", Ci.nsIFile);
+ Services.env.set("DYLD_LIBRARY_PATH", greBinDir.path);
+ // For Linux
+ Services.env.set("LD_LIBRARY_PATH", greBinDir.path);
+ // XXX: handle windows
+}
diff --git a/xpcom/tests/unit/test_bug121341.js b/xpcom/tests/unit/test_bug121341.js
new file mode 100644
index 0000000000..2796fc47f2
--- /dev/null
+++ b/xpcom/tests/unit/test_bug121341.js
@@ -0,0 +1,62 @@
+const { NetUtil } = ChromeUtils.import("resource://gre/modules/NetUtil.jsm");
+
+function run_test() {
+ var dataFile = do_get_file("data/bug121341.properties");
+ var channel = NetUtil.newChannel({
+ uri: Services.io.newFileURI(dataFile, null, null),
+ loadUsingSystemPrincipal: true,
+ });
+ var inp = channel.open();
+
+ var properties = Cu.createPersistentProperties();
+ properties.load(inp);
+
+ var value;
+
+ value = properties.getStringProperty("1");
+ Assert.equal(value, "abc");
+
+ value = properties.getStringProperty("2");
+ Assert.equal(value, "xy");
+
+ value = properties.getStringProperty("3");
+ Assert.equal(value, "\u1234\t\r\n\u00AB\u0001\n");
+
+ value = properties.getStringProperty("4");
+ Assert.equal(value, "this is multiline property");
+
+ value = properties.getStringProperty("5");
+ Assert.equal(value, "this is another multiline property");
+
+ value = properties.getStringProperty("6");
+ Assert.equal(value, "test\u0036");
+
+ value = properties.getStringProperty("7");
+ Assert.equal(value, "yet another multiline propery");
+
+ value = properties.getStringProperty("8");
+ Assert.equal(value, "\ttest5\u0020");
+
+ value = properties.getStringProperty("9");
+ Assert.equal(value, " test6\t");
+
+ value = properties.getStringProperty("10a\u1234b");
+ Assert.equal(value, "c\uCDEFd");
+
+ value = properties.getStringProperty("11");
+ Assert.equal(value, "\uABCD");
+
+ dataFile = do_get_file("data/bug121341-2.properties");
+
+ var channel2 = NetUtil.newChannel({
+ uri: Services.io.newFileURI(dataFile, null, null),
+ loadUsingSystemPrincipal: true,
+ });
+ inp = channel2.open();
+
+ var properties2 = Cu.createPersistentProperties();
+ try {
+ properties2.load(inp);
+ do_throw("load() didn't fail");
+ } catch (e) {}
+}
diff --git a/xpcom/tests/unit/test_bug1434856.js b/xpcom/tests/unit/test_bug1434856.js
new file mode 100644
index 0000000000..a8dfa08079
--- /dev/null
+++ b/xpcom/tests/unit/test_bug1434856.js
@@ -0,0 +1,27 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/ */
+
+function run_test() {
+ let complete = false;
+
+ let runnable = {
+ internalQI: ChromeUtils.generateQI(["nsIRunnable"]),
+ // eslint-disable-next-line mozilla/use-chromeutils-generateqi
+ QueryInterface(iid) {
+ // Attempt to schedule another runnable. This simulates a GC/CC
+ // being scheduled while executing the JS QI.
+ Services.tm.dispatchToMainThread(() => false);
+ return this.internalQI(iid);
+ },
+
+ run() {
+ complete = true;
+ },
+ };
+
+ Services.tm.dispatchToMainThread(runnable);
+ Services.tm.spinEventLoopUntil(
+ "Test(test_bug1434856.js:run_test)",
+ () => complete
+ );
+}
diff --git a/xpcom/tests/unit/test_bug325418.js b/xpcom/tests/unit/test_bug325418.js
new file mode 100644
index 0000000000..5840aacf74
--- /dev/null
+++ b/xpcom/tests/unit/test_bug325418.js
@@ -0,0 +1,72 @@
+// 5 seconds.
+const kExpectedDelay1 = 5;
+// 1 second.
+const kExpectedDelay2 = 1;
+
+var gStartTime1;
+var gStartTime2;
+var timer;
+
+var observer1 = {
+ observe: function observeTC1(subject, topic, data) {
+ if (topic == "timer-callback") {
+ // Stop timer, so it doesn't repeat (if test runs slowly).
+ timer.cancel();
+
+ // Actual delay may not be exact, so convert to seconds and round.
+ Assert.equal(
+ Math.round((Date.now() - gStartTime1) / 1000),
+ kExpectedDelay1
+ );
+
+ timer = null;
+
+ info(
+ "1st timer triggered (before being cancelled). Should not have happened!"
+ );
+ Assert.ok(false);
+ }
+ },
+};
+
+var observer2 = {
+ observe: function observeTC2(subject, topic, data) {
+ if (topic == "timer-callback") {
+ // Stop timer, so it doesn't repeat (if test runs slowly).
+ timer.cancel();
+
+ // Actual delay may not be exact, so convert to seconds and round.
+ Assert.equal(
+ Math.round((Date.now() - gStartTime2) / 1000),
+ kExpectedDelay2
+ );
+
+ timer = null;
+
+ do_test_finished();
+ }
+ },
+};
+
+function run_test() {
+ do_test_pending();
+
+ timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
+
+ // Initialize the timer (with some delay), then cancel it.
+ gStartTime1 = Date.now();
+ timer.init(
+ observer1,
+ kExpectedDelay1 * 1000,
+ timer.TYPE_REPEATING_PRECISE_CAN_SKIP
+ );
+ timer.cancel();
+
+ // Re-initialize the timer (with a different delay).
+ gStartTime2 = Date.now();
+ timer.init(
+ observer2,
+ kExpectedDelay2 * 1000,
+ timer.TYPE_REPEATING_PRECISE_CAN_SKIP
+ );
+}
diff --git a/xpcom/tests/unit/test_bug332389.js b/xpcom/tests/unit/test_bug332389.js
new file mode 100644
index 0000000000..605772f12a
--- /dev/null
+++ b/xpcom/tests/unit/test_bug332389.js
@@ -0,0 +1,14 @@
+function run_test() {
+ var f = Services.dirsvc.get("CurProcD", Ci.nsIFile);
+
+ var terminated = false;
+ for (var i = 0; i < 100; i++) {
+ if (f == null) {
+ terminated = true;
+ break;
+ }
+ f = f.parent;
+ }
+
+ Assert.ok(terminated);
+}
diff --git a/xpcom/tests/unit/test_bug333505.js b/xpcom/tests/unit/test_bug333505.js
new file mode 100644
index 0000000000..97016519da
--- /dev/null
+++ b/xpcom/tests/unit/test_bug333505.js
@@ -0,0 +1,10 @@
+function run_test() {
+ var dirEntries = do_get_cwd().directoryEntries;
+
+ while (dirEntries.hasMoreElements()) {
+ dirEntries.getNext();
+ }
+
+ // We ensure there is no crash
+ dirEntries.hasMoreElements();
+}
diff --git a/xpcom/tests/unit/test_bug364285-1.js b/xpcom/tests/unit/test_bug364285-1.js
new file mode 100644
index 0000000000..167e94e852
--- /dev/null
+++ b/xpcom/tests/unit/test_bug364285-1.js
@@ -0,0 +1,43 @@
+var nameArray = [
+ "ascii", // ASCII
+ "fran\u00E7ais", // Latin-1
+ "\u0420\u0443\u0441\u0441\u043A\u0438\u0439", // Cyrillic
+ "\u65E5\u672C\u8A9E", // Japanese
+ "\u4E2D\u6587", // Chinese
+ "\uD55C\uAD6D\uC5B4", // Korean
+ "\uD801\uDC0F\uD801\uDC2D\uD801\uDC3B\uD801\uDC2B", // Deseret
+];
+
+function getTempDir() {
+ return Services.dirsvc.get("TmpD", Ci.nsIFile);
+}
+
+function create_file(fileName) {
+ var outFile = getTempDir();
+ outFile.append(fileName);
+ outFile.createUnique(outFile.NORMAL_FILE_TYPE, 0o600);
+
+ var stream = Cc["@mozilla.org/network/file-output-stream;1"].createInstance(
+ Ci.nsIFileOutputStream
+ );
+ stream.init(outFile, 0x02 | 0x08 | 0x20, 0o600, 0);
+ stream.write("foo", 3);
+ stream.close();
+
+ Assert.equal(outFile.leafName.substr(0, fileName.length), fileName);
+
+ return outFile;
+}
+
+function test_create(fileName) {
+ var file1 = create_file(fileName);
+ var file2 = create_file(fileName);
+ file1.remove(false);
+ file2.remove(false);
+}
+
+function run_test() {
+ for (var i = 0; i < nameArray.length; ++i) {
+ test_create(nameArray[i]);
+ }
+}
diff --git a/xpcom/tests/unit/test_bug374754.js b/xpcom/tests/unit/test_bug374754.js
new file mode 100644
index 0000000000..0d20d90b2c
--- /dev/null
+++ b/xpcom/tests/unit/test_bug374754.js
@@ -0,0 +1,65 @@
+var addedTopic = "xpcom-category-entry-added";
+var removedTopic = "xpcom-category-entry-removed";
+var testCategory = "bug-test-category";
+var testEntry = "@mozilla.org/bug-test-entry;1";
+
+var testValue = "check validity";
+var result = "";
+var expected = "add remove add remove ";
+var timer;
+
+var observer = {
+ QueryInterface: ChromeUtils.generateQI(["nsIObserver"]),
+
+ observe(subject, topic, data) {
+ if (topic == "timer-callback") {
+ Assert.equal(result, expected);
+
+ Services.obs.removeObserver(this, addedTopic);
+ Services.obs.removeObserver(this, removedTopic);
+
+ do_test_finished();
+
+ timer = null;
+ }
+
+ if (
+ subject.QueryInterface(Ci.nsISupportsCString).data != testEntry ||
+ data != testCategory
+ ) {
+ return;
+ }
+
+ if (topic == addedTopic) {
+ result += "add ";
+ } else if (topic == removedTopic) {
+ result += "remove ";
+ }
+ },
+};
+
+function run_test() {
+ do_test_pending();
+
+ Services.obs.addObserver(observer, addedTopic);
+ Services.obs.addObserver(observer, removedTopic);
+
+ Services.catMan.addCategoryEntry(
+ testCategory,
+ testEntry,
+ testValue,
+ false,
+ true
+ );
+ Services.catMan.addCategoryEntry(
+ testCategory,
+ testEntry,
+ testValue,
+ false,
+ true
+ );
+ Services.catMan.deleteCategoryEntry(testCategory, testEntry, false);
+
+ timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
+ timer.init(observer, 0, timer.TYPE_ONE_SHOT);
+}
diff --git a/xpcom/tests/unit/test_bug476919.js b/xpcom/tests/unit/test_bug476919.js
new file mode 100644
index 0000000000..5ba64758c7
--- /dev/null
+++ b/xpcom/tests/unit/test_bug476919.js
@@ -0,0 +1,25 @@
+/* global __LOCATION__ */
+
+function run_test() {
+ var testDir = __LOCATION__.parent;
+ // create a test file, then symlink it, then check that we think it's a symlink
+ var targetFile = testDir.clone();
+ targetFile.append("target.txt");
+ if (!targetFile.exists()) {
+ targetFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0o644);
+ }
+
+ var link = testDir.clone();
+ link.append("link");
+ if (link.exists()) {
+ link.remove(false);
+ }
+
+ var ln = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
+ ln.initWithPath("/bin/ln");
+ var process = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess);
+ process.init(ln);
+ var args = ["-s", targetFile.path, link.path];
+ process.run(true, args, args.length);
+ Assert.ok(link.isSymlink());
+}
diff --git a/xpcom/tests/unit/test_bug478086.js b/xpcom/tests/unit/test_bug478086.js
new file mode 100644
index 0000000000..6debb58fbc
--- /dev/null
+++ b/xpcom/tests/unit/test_bug478086.js
@@ -0,0 +1,23 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/ */
+
+function run_test() {
+ var nsIFile = Ci.nsIFile;
+ var root = Cc["@mozilla.org/file/local;1"].createInstance(nsIFile);
+
+ // copied from http://mxr.mozilla.org/mozilla-central/source/image/test/unit/test_imgtools.js#135
+ // nsIXULRuntime.OS doesn't seem to be available in xpcshell, so we'll use
+ // this as a kludgy way to figure out if we're running on Windows.
+ if (mozinfo.os == "win") {
+ root.initWithPath("\\\\.");
+ } else {
+ return; // XXX disabled, since this causes intermittent failures on Mac (bug 481369).
+ // root.initWithPath("/");
+ }
+ var drives = root.directoryEntries;
+ Assert.ok(drives.hasMoreElements());
+ while (drives.hasMoreElements()) {
+ var newPath = drives.nextFile.path;
+ Assert.equal(newPath.indexOf("\0"), -1);
+ }
+}
diff --git a/xpcom/tests/unit/test_bug745466.js b/xpcom/tests/unit/test_bug745466.js
new file mode 100644
index 0000000000..a655bf45b4
--- /dev/null
+++ b/xpcom/tests/unit/test_bug745466.js
@@ -0,0 +1,7 @@
+const { FileUtils } = ChromeUtils.importESModule(
+ "resource://gre/modules/FileUtils.sys.mjs"
+);
+
+function run_test() {
+ Assert.ok(FileUtils.File("~").equals(FileUtils.getDir("Home", [])));
+}
diff --git a/xpcom/tests/unit/test_debugger_malloc_size_of.js b/xpcom/tests/unit/test_debugger_malloc_size_of.js
new file mode 100644
index 0000000000..3141d8c2c3
--- /dev/null
+++ b/xpcom/tests/unit/test_debugger_malloc_size_of.js
@@ -0,0 +1,32 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// This is just a sanity test that Gecko is giving SpiderMonkey a MallocSizeOf
+// function for new JSRuntimes. There is more extensive testing around the
+// expected byte sizes within SpiderMonkey's jit-tests, we just want to make
+// sure that Gecko is providing SpiderMonkey with the callback it needs.
+
+const { byteSize } = Cu.getJSTestingFunctions();
+
+function run_test() {
+ const objects = [
+ {},
+ { w: 1, x: 2, y: 3, z: 4, a: 5 },
+ [],
+ Array(10).fill(null),
+ new RegExp("(2|two) problems", "g"),
+ new Date(),
+ new Uint8Array(64),
+ Promise.resolve(1),
+ function f() {},
+ Object,
+ ];
+
+ for (let obj of objects) {
+ info(uneval(obj));
+ ok(byteSize(obj), "We should get some (non-zero) byte size");
+ }
+}
diff --git a/xpcom/tests/unit/test_file_createUnique.js b/xpcom/tests/unit/test_file_createUnique.js
new file mode 100644
index 0000000000..510002bda2
--- /dev/null
+++ b/xpcom/tests/unit/test_file_createUnique.js
@@ -0,0 +1,29 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+function run_test() {
+ // Generate a leaf name that is 255 characters long.
+ var longLeafName = new Array(256).join("T");
+
+ // Generate the path for a file located in a directory with a long name.
+ var tempFile = Services.dirsvc.get("TmpD", Ci.nsIFile);
+ tempFile.append(longLeafName);
+ tempFile.append("test.txt");
+
+ try {
+ tempFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o600);
+ do_throw("Creating an item in a folder with a very long name should throw");
+ } catch (e) {
+ if (
+ !(
+ e instanceof Ci.nsIException &&
+ e.result == Cr.NS_ERROR_FILE_UNRECOGNIZED_PATH
+ )
+ ) {
+ throw e;
+ }
+ // We expect the function not to crash but to raise this exception.
+ }
+}
diff --git a/xpcom/tests/unit/test_file_equality.js b/xpcom/tests/unit/test_file_equality.js
new file mode 100644
index 0000000000..74ea8046d8
--- /dev/null
+++ b/xpcom/tests/unit/test_file_equality.js
@@ -0,0 +1,37 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+var LocalFile = CC("@mozilla.org/file/local;1", "nsIFile", "initWithPath");
+
+function run_test() {
+ test_normalized_vs_non_normalized();
+}
+
+function test_normalized_vs_non_normalized() {
+ // get a directory that exists on all platforms
+ var tmp1 = Services.dirsvc.get("TmpD", Ci.nsIFile);
+ var exists = tmp1.exists();
+ Assert.ok(exists);
+ if (!exists) {
+ return;
+ }
+
+ // the test logic below assumes we're starting with a normalized path, but the
+ // default location on macos is a symbolic link, so resolve it before starting
+ tmp1.normalize();
+
+ // this has the same exact path as tmp1, it should equal tmp1
+ var tmp2 = new LocalFile(tmp1.path);
+ Assert.ok(tmp1.equals(tmp2));
+
+ // this is a non-normalized version of tmp1, it should not equal tmp1
+ tmp2.appendRelativePath(".");
+ Assert.ok(!tmp1.equals(tmp2));
+
+ // normalize and make sure they are equivalent again
+ tmp2.normalize();
+ Assert.ok(tmp1.equals(tmp2));
+}
diff --git a/xpcom/tests/unit/test_file_renameTo.js b/xpcom/tests/unit/test_file_renameTo.js
new file mode 100644
index 0000000000..a6e8633773
--- /dev/null
+++ b/xpcom/tests/unit/test_file_renameTo.js
@@ -0,0 +1,55 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+function run_test() {
+ // Create the base directory.
+ let base = Services.dirsvc.get("TmpD", Ci.nsIFile);
+ base.append("renameTesting");
+ if (base.exists()) {
+ base.remove(true);
+ }
+ base.create(Ci.nsIFile.DIRECTORY_TYPE, parseInt("0777", 8));
+
+ // Create a sub directory under the base.
+ let subdir = base.clone();
+ subdir.append("subdir");
+ subdir.create(Ci.nsIFile.DIRECTORY_TYPE, parseInt("0777", 8));
+
+ // Create a file under the sub directory.
+ let tempFile = subdir.clone();
+ tempFile.append("file0.txt");
+ tempFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, parseInt("0777", 8));
+
+ // Test renameTo in the base directory
+ tempFile.renameTo(null, "file1.txt");
+ Assert.ok(exists(subdir, "file1.txt"));
+
+ // Test moving across directories
+ tempFile = subdir.clone();
+ tempFile.append("file1.txt");
+ tempFile.renameTo(base, "");
+ Assert.ok(exists(base, "file1.txt"));
+
+ // Test moving across directories and renaming at the same time
+ tempFile = base.clone();
+ tempFile.append("file1.txt");
+ tempFile.renameTo(subdir, "file2.txt");
+ Assert.ok(exists(subdir, "file2.txt"));
+
+ // Test moving a directory
+ subdir.renameTo(base, "renamed");
+ Assert.ok(exists(base, "renamed"));
+ let renamed = base.clone();
+ renamed.append("renamed");
+ Assert.ok(exists(renamed, "file2.txt"));
+
+ base.remove(true);
+}
+
+function exists(parent, filename) {
+ let file = parent.clone();
+ file.append(filename);
+ return file.exists();
+}
diff --git a/xpcom/tests/unit/test_hidden_files.js b/xpcom/tests/unit/test_hidden_files.js
new file mode 100644
index 0000000000..27d87e6f54
--- /dev/null
+++ b/xpcom/tests/unit/test_hidden_files.js
@@ -0,0 +1,24 @@
+const NS_OS_TEMP_DIR = "TmpD";
+
+var hiddenUnixFile;
+function createUNIXHiddenFile() {
+ var tmpDir = Services.dirsvc.get(NS_OS_TEMP_DIR, Ci.nsIFile);
+ hiddenUnixFile = tmpDir.clone();
+ hiddenUnixFile.append(".foo");
+ // we don't care if this already exists because we don't care
+ // about the file's contents (just the name)
+ if (!hiddenUnixFile.exists()) {
+ hiddenUnixFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0o666);
+ }
+ return hiddenUnixFile.exists();
+}
+
+function run_test() {
+ // Skip this test on Windows
+ if (mozinfo.os == "win") {
+ return;
+ }
+
+ Assert.ok(createUNIXHiddenFile());
+ Assert.ok(hiddenUnixFile.isHidden());
+}
diff --git a/xpcom/tests/unit/test_home.js b/xpcom/tests/unit/test_home.js
new file mode 100644
index 0000000000..e3a4af9796
--- /dev/null
+++ b/xpcom/tests/unit/test_home.js
@@ -0,0 +1,18 @@
+const CWD = do_get_cwd();
+function checkOS(os) {
+ const nsILocalFile_ = "nsILocalFile" + os;
+ return nsILocalFile_ in Ci && CWD instanceof Ci[nsILocalFile_];
+}
+
+const isWin = checkOS("Win");
+
+function run_test() {
+ var envVar = isWin ? "USERPROFILE" : "HOME";
+
+ var homeDir = Services.dirsvc.get("Home", Ci.nsIFile);
+
+ var expected = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
+ expected.initWithPath(Services.env.get(envVar));
+
+ Assert.equal(homeDir.path, expected.path);
+}
diff --git a/xpcom/tests/unit/test_iniParser.js b/xpcom/tests/unit/test_iniParser.js
new file mode 100644
index 0000000000..a586c4c060
--- /dev/null
+++ b/xpcom/tests/unit/test_iniParser.js
@@ -0,0 +1,476 @@
+var testnum = 0;
+var factory;
+
+function parserForFile(filename) {
+ let parser = null;
+ try {
+ let file = do_get_file(filename);
+ Assert.ok(!!file);
+ parser = factory.createINIParser(file);
+ Assert.ok(!!parser);
+ } catch (e) {
+ dump("INFO | caught error: " + e);
+ // checkParserOutput will handle a null parser when it's expected.
+ }
+ return parser;
+}
+
+function checkParserOutput(parser, expected) {
+ // If the expected output is null, we expect the parser to have
+ // failed (and vice-versa).
+ if (!parser || !expected) {
+ Assert.equal(parser, null);
+ Assert.equal(expected, null);
+ return;
+ }
+
+ let output = getParserOutput(parser);
+ for (let section in expected) {
+ Assert.ok(section in output);
+ for (let key in expected[section]) {
+ Assert.ok(key in output[section]);
+ Assert.equal(output[section][key], expected[section][key]);
+ delete output[section][key];
+ }
+ for (let key in output[section]) {
+ Assert.equal(key, "wasn't expecting this key!");
+ }
+ delete output[section];
+ }
+ for (let section in output) {
+ Assert.equal(section, "wasn't expecting this section!");
+ }
+}
+
+function getParserOutput(parser) {
+ let output = {};
+
+ for (let section of parser.getSections()) {
+ Assert.equal(false, section in output); // catch dupes
+ output[section] = {};
+
+ for (let key of parser.getKeys(section)) {
+ Assert.equal(false, key in output[section]); // catch dupes
+ let value = parser.getString(section, key);
+ output[section][key] = value;
+ }
+ }
+ return output;
+}
+
+function run_test() {
+ try {
+ var testdata = [
+ { filename: "data/iniparser01.ini", reference: {} },
+ { filename: "data/iniparser02.ini", reference: {} },
+ { filename: "data/iniparser03.ini", reference: {} },
+ { filename: "data/iniparser04.ini", reference: {} },
+ { filename: "data/iniparser05.ini", reference: {} },
+ { filename: "data/iniparser06.ini", reference: {} },
+ { filename: "data/iniparser07.ini", reference: {} },
+ {
+ filename: "data/iniparser08.ini",
+ reference: { section1: { name1: "" } },
+ },
+ {
+ filename: "data/iniparser09.ini",
+ reference: { section1: { name1: "value1" } },
+ },
+ {
+ filename: "data/iniparser10.ini",
+ reference: { section1: { name1: "value1" } },
+ },
+ {
+ filename: "data/iniparser11.ini",
+ reference: { section1: { name1: "value1" } },
+ },
+ {
+ filename: "data/iniparser12.ini",
+ reference: { section1: { name1: "value1" } },
+ },
+ {
+ filename: "data/iniparser13.ini",
+ reference: { section1: { name1: "value1" } },
+ },
+ {
+ filename: "data/iniparser14.ini",
+ reference: {
+ section1: { name1: "value1", name2: "value2" },
+ section2: { name1: "value1", name2: "foopy" },
+ },
+ },
+ {
+ filename: "data/iniparser15.ini",
+ reference: {
+ section1: { name1: "newValue1" },
+ section2: { name1: "foopy" },
+ },
+ },
+ {
+ filename: "data/iniparser16.ini",
+ reference: {
+ "☺♫": { "♫": "☻", "♪": "♥" },
+ "☼": { "♣": "♠", "♦": "♥" },
+ },
+ },
+ { filename: "data/iniparser17.ini", reference: { section: { key: "" } } },
+ ];
+
+ testdata.push({
+ filename: "data/iniparser01-utf8BOM.ini",
+ reference: testdata[0].reference,
+ });
+ testdata.push({
+ filename: "data/iniparser02-utf8BOM.ini",
+ reference: testdata[1].reference,
+ });
+ testdata.push({
+ filename: "data/iniparser03-utf8BOM.ini",
+ reference: testdata[2].reference,
+ });
+ testdata.push({
+ filename: "data/iniparser04-utf8BOM.ini",
+ reference: testdata[3].reference,
+ });
+ testdata.push({
+ filename: "data/iniparser05-utf8BOM.ini",
+ reference: testdata[4].reference,
+ });
+ testdata.push({
+ filename: "data/iniparser06-utf8BOM.ini",
+ reference: testdata[5].reference,
+ });
+ testdata.push({
+ filename: "data/iniparser07-utf8BOM.ini",
+ reference: testdata[6].reference,
+ });
+ testdata.push({
+ filename: "data/iniparser08-utf8BOM.ini",
+ reference: testdata[7].reference,
+ });
+ testdata.push({
+ filename: "data/iniparser09-utf8BOM.ini",
+ reference: testdata[8].reference,
+ });
+ testdata.push({
+ filename: "data/iniparser10-utf8BOM.ini",
+ reference: testdata[9].reference,
+ });
+ testdata.push({
+ filename: "data/iniparser11-utf8BOM.ini",
+ reference: testdata[10].reference,
+ });
+ testdata.push({
+ filename: "data/iniparser12-utf8BOM.ini",
+ reference: testdata[11].reference,
+ });
+ testdata.push({
+ filename: "data/iniparser13-utf8BOM.ini",
+ reference: testdata[12].reference,
+ });
+ testdata.push({
+ filename: "data/iniparser14-utf8BOM.ini",
+ reference: testdata[13].reference,
+ });
+ testdata.push({
+ filename: "data/iniparser15-utf8BOM.ini",
+ reference: testdata[14].reference,
+ });
+ testdata.push({
+ filename: "data/iniparser16-utf8BOM.ini",
+ reference: testdata[15].reference,
+ });
+
+ // Intentional test for appInfo that can't be preloaded.
+ // eslint-disable-next-line mozilla/use-services
+ let os = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime).OS;
+ if ("WINNT" === os) {
+ testdata.push({
+ filename: "data/iniparser01-utf16leBOM.ini",
+ reference: testdata[0].reference,
+ });
+ testdata.push({
+ filename: "data/iniparser02-utf16leBOM.ini",
+ reference: testdata[1].reference,
+ });
+ testdata.push({
+ filename: "data/iniparser03-utf16leBOM.ini",
+ reference: testdata[2].reference,
+ });
+ testdata.push({
+ filename: "data/iniparser04-utf16leBOM.ini",
+ reference: testdata[3].reference,
+ });
+ testdata.push({
+ filename: "data/iniparser05-utf16leBOM.ini",
+ reference: testdata[4].reference,
+ });
+ testdata.push({
+ filename: "data/iniparser06-utf16leBOM.ini",
+ reference: testdata[5].reference,
+ });
+ testdata.push({
+ filename: "data/iniparser07-utf16leBOM.ini",
+ reference: testdata[6].reference,
+ });
+ testdata.push({
+ filename: "data/iniparser08-utf16leBOM.ini",
+ reference: testdata[7].reference,
+ });
+ testdata.push({
+ filename: "data/iniparser09-utf16leBOM.ini",
+ reference: testdata[8].reference,
+ });
+ testdata.push({
+ filename: "data/iniparser10-utf16leBOM.ini",
+ reference: testdata[9].reference,
+ });
+ testdata.push({
+ filename: "data/iniparser11-utf16leBOM.ini",
+ reference: testdata[10].reference,
+ });
+ testdata.push({
+ filename: "data/iniparser12-utf16leBOM.ini",
+ reference: testdata[11].reference,
+ });
+ testdata.push({
+ filename: "data/iniparser13-utf16leBOM.ini",
+ reference: testdata[12].reference,
+ });
+ testdata.push({
+ filename: "data/iniparser14-utf16leBOM.ini",
+ reference: testdata[13].reference,
+ });
+ testdata.push({
+ filename: "data/iniparser15-utf16leBOM.ini",
+ reference: testdata[14].reference,
+ });
+ testdata.push({
+ filename: "data/iniparser16-utf16leBOM.ini",
+ reference: testdata[15].reference,
+ });
+ }
+
+ /* ========== 0 ========== */
+ factory = Cc["@mozilla.org/xpcom/ini-parser-factory;1"].getService(
+ Ci.nsIINIParserFactory
+ );
+ Assert.ok(!!factory);
+
+ // Test reading from a variety of files and strings. While we're at it,
+ // write out each one and read it back to ensure that nothing changed.
+ while (testnum < testdata.length) {
+ dump("\nINFO | test #" + ++testnum);
+ let filename = testdata[testnum - 1].filename;
+ dump(", filename " + filename + "\n");
+ let parser = parserForFile(filename);
+ checkParserOutput(parser, testdata[testnum - 1].reference);
+ if (!parser) {
+ continue;
+ }
+ Assert.ok(parser instanceof Ci.nsIINIParserWriter);
+ // write contents out to a new file
+ let newfilename = filename + ".new";
+ let newfile = do_get_file(filename);
+ newfile.leafName += ".new";
+ parser.writeFile(newfile);
+ // read new file and make sure the contents are the same.
+ parser = parserForFile(newfilename);
+ checkParserOutput(parser, testdata[testnum - 1].reference);
+ // cleanup after the test
+ newfile.remove(false);
+
+ // ensure that `writeString` works correctly
+ Assert.ok(parser instanceof Ci.nsIINIParserWriter);
+ let formatted = parser.writeToString();
+ parser = factory.createINIParser(null);
+ // re-parsing the formatted string is the easiest
+ // way to verify correctness...
+ parser.initFromString(formatted);
+ checkParserOutput(parser, testdata[testnum - 1].reference);
+ }
+
+ dump("INFO | test #" + ++testnum + "\n");
+
+ // test writing to a new file.
+ var newfile = do_get_file("data/");
+ newfile.append("nonexistent-file.ini");
+ if (newfile.exists()) {
+ newfile.remove(false);
+ }
+ Assert.ok(!newfile.exists());
+
+ try {
+ var parser = factory.createINIParser(newfile);
+ Assert.ok(false, "Should have thrown an exception");
+ } catch (e) {
+ Assert.equal(
+ e.result,
+ Cr.NS_ERROR_FILE_NOT_FOUND,
+ "Caught a file not found exception"
+ );
+ }
+ parser = factory.createINIParser();
+ Assert.ok(!!parser);
+ Assert.ok(parser instanceof Ci.nsIINIParserWriter);
+ checkParserOutput(parser, {});
+ parser.writeFile(newfile);
+ Assert.ok(newfile.exists());
+
+ // test adding a new section and new key
+ parser.setString("section", "key", "value");
+ parser.setString("section", "key2", "");
+ parser.writeFile(newfile);
+ Assert.ok(newfile.exists());
+ checkParserOutput(parser, { section: { key: "value", key2: "" } });
+ // read it in again, check for same data.
+ parser = parserForFile("data/nonexistent-file.ini");
+ checkParserOutput(parser, { section: { key: "value", key2: "" } });
+ // cleanup after the test
+ newfile.remove(false);
+
+ dump("INFO | test #" + ++testnum + "\n");
+
+ // test modifying a existing key's value (in an existing section)
+ parser = parserForFile("data/iniparser09.ini");
+ checkParserOutput(parser, { section1: { name1: "value1" } });
+
+ Assert.ok(parser instanceof Ci.nsIINIParserWriter);
+ parser.setString("section1", "name1", "value2");
+ checkParserOutput(parser, { section1: { name1: "value2" } });
+
+ dump("INFO | test #" + ++testnum + "\n");
+
+ // test trying to set illegal characters
+ var caughtError;
+ caughtError = null;
+ checkParserOutput(parser, { section1: { name1: "value2" } });
+
+ // Bad characters in section name
+ try {
+ parser.setString("bad\0", "ok", "ok");
+ } catch (e) {
+ caughtError = e;
+ }
+ Assert.ok(caughtError);
+ Assert.equal(caughtError.result, Cr.NS_ERROR_INVALID_ARG);
+ caughtError = null;
+ try {
+ parser.setString("bad\r", "ok", "ok");
+ } catch (e) {
+ caughtError = e;
+ }
+ Assert.ok(caughtError);
+ Assert.equal(caughtError.result, Cr.NS_ERROR_INVALID_ARG);
+ caughtError = null;
+ try {
+ parser.setString("bad\n", "ok", "ok");
+ } catch (e) {
+ caughtError = e;
+ }
+ Assert.ok(caughtError);
+ Assert.equal(caughtError.result, Cr.NS_ERROR_INVALID_ARG);
+ caughtError = null;
+ try {
+ parser.setString("bad[", "ok", "ok");
+ } catch (e) {
+ caughtError = e;
+ }
+ Assert.ok(caughtError);
+ Assert.equal(caughtError.result, Cr.NS_ERROR_INVALID_ARG);
+ caughtError = null;
+ try {
+ parser.setString("bad]", "ok", "ok");
+ } catch (e) {
+ caughtError = e;
+ }
+ Assert.ok(caughtError);
+ Assert.equal(caughtError.result, Cr.NS_ERROR_INVALID_ARG);
+ caughtError = null;
+ try {
+ parser.setString("", "ok", "ok");
+ } catch (e) {
+ caughtError = e;
+ }
+ Assert.ok(caughtError);
+ Assert.equal(caughtError.result, Cr.NS_ERROR_INVALID_ARG);
+
+ // Bad characters in key name
+ caughtError = null;
+ try {
+ parser.setString("ok", "bad\0", "ok");
+ } catch (e) {
+ caughtError = e;
+ }
+ Assert.ok(caughtError);
+ Assert.equal(caughtError.result, Cr.NS_ERROR_INVALID_ARG);
+ caughtError = null;
+ try {
+ parser.setString("ok", "bad\r", "ok");
+ } catch (e) {
+ caughtError = e;
+ }
+ Assert.ok(caughtError);
+ Assert.equal(caughtError.result, Cr.NS_ERROR_INVALID_ARG);
+ caughtError = null;
+ try {
+ parser.setString("ok", "bad\n", "ok");
+ } catch (e) {
+ caughtError = e;
+ }
+ Assert.ok(caughtError);
+ Assert.equal(caughtError.result, Cr.NS_ERROR_INVALID_ARG);
+ caughtError = null;
+ try {
+ parser.setString("ok", "bad=", "ok");
+ } catch (e) {
+ caughtError = e;
+ }
+ Assert.ok(caughtError);
+ Assert.equal(caughtError.result, Cr.NS_ERROR_INVALID_ARG);
+ caughtError = null;
+ try {
+ parser.setString("ok", "", "ok");
+ } catch (e) {
+ caughtError = e;
+ }
+ Assert.ok(caughtError);
+ Assert.equal(caughtError.result, Cr.NS_ERROR_INVALID_ARG);
+
+ // Bad characters in value
+ caughtError = null;
+ try {
+ parser.setString("ok", "ok", "bad\0");
+ } catch (e) {
+ caughtError = e;
+ }
+ Assert.ok(caughtError);
+ Assert.equal(caughtError.result, Cr.NS_ERROR_INVALID_ARG);
+ caughtError = null;
+ try {
+ parser.setString("ok", "ok", "bad\r");
+ } catch (e) {
+ caughtError = e;
+ }
+ Assert.ok(caughtError);
+ Assert.equal(caughtError.result, Cr.NS_ERROR_INVALID_ARG);
+ caughtError = null;
+ try {
+ parser.setString("ok", "ok", "bad\n");
+ } catch (e) {
+ caughtError = e;
+ }
+ Assert.ok(caughtError);
+ Assert.equal(caughtError.result, Cr.NS_ERROR_INVALID_ARG);
+ caughtError = null;
+ try {
+ parser.setString("ok", "ok", "good=");
+ } catch (e) {
+ caughtError = e;
+ }
+ Assert.ok(!caughtError);
+ caughtError = null;
+ } catch (e) {
+ throw new Error(`FAILED in test #${testnum} -- ${e}`);
+ }
+}
diff --git a/xpcom/tests/unit/test_ioutil.js b/xpcom/tests/unit/test_ioutil.js
new file mode 100644
index 0000000000..e269b424a2
--- /dev/null
+++ b/xpcom/tests/unit/test_ioutil.js
@@ -0,0 +1,29 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 4 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+const util = Cc["@mozilla.org/io-util;1"].getService(Ci.nsIIOUtil);
+
+function run_test() {
+ try {
+ util.inputStreamIsBuffered(null);
+ do_throw("inputStreamIsBuffered should have thrown");
+ } catch (e) {
+ Assert.equal(e.result, Cr.NS_ERROR_INVALID_POINTER);
+ }
+
+ try {
+ util.outputStreamIsBuffered(null);
+ do_throw("outputStreamIsBuffered should have thrown");
+ } catch (e) {
+ Assert.equal(e.result, Cr.NS_ERROR_INVALID_POINTER);
+ }
+
+ var s = Cc["@mozilla.org/io/string-input-stream;1"].createInstance(
+ Ci.nsIStringInputStream
+ );
+ var body = "This is a test";
+ s.setData(body, body.length);
+ Assert.equal(util.inputStreamIsBuffered(s), true);
+}
diff --git a/xpcom/tests/unit/test_localfile.js b/xpcom/tests/unit/test_localfile.js
new file mode 100644
index 0000000000..c90d91b278
--- /dev/null
+++ b/xpcom/tests/unit/test_localfile.js
@@ -0,0 +1,288 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+const { AppConstants } = ChromeUtils.importESModule(
+ "resource://gre/modules/AppConstants.sys.mjs"
+);
+const { setTimeout } = ChromeUtils.importESModule(
+ "resource://gre/modules/Timer.sys.mjs"
+);
+
+const MAX_TIME_DIFFERENCE = 2500;
+const MILLIS_PER_DAY = 1000 * 60 * 60 * 24;
+
+var LocalFile = CC("@mozilla.org/file/local;1", "nsIFile", "initWithPath");
+
+function sleep(ms) {
+ // We are measuring timestamps, which are slightly fuzzed, and just need to
+ // measure that they are increasing.
+ // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
+ return new Promise(resolve => setTimeout(() => resolve(), ms));
+}
+
+add_task(function test_toplevel_parent_is_null() {
+ try {
+ var lf = new LocalFile("C:\\");
+
+ // not required by API, but a property on which the implementation of
+ // parent == null relies for correctness
+ Assert.ok(lf.path.length == 2);
+
+ Assert.ok(lf.parent === null);
+ } catch (e) {
+ // not Windows
+ Assert.equal(e.result, Cr.NS_ERROR_FILE_UNRECOGNIZED_PATH);
+ }
+});
+
+add_task(function test_normalize_crash_if_media_missing() {
+ const a = "a".charCodeAt(0);
+ const z = "z".charCodeAt(0);
+ for (var i = a; i <= z; ++i) {
+ try {
+ LocalFile(String.fromCharCode(i) + ":.\\test").normalize();
+ } catch (e) {}
+ }
+});
+
+// Tests that changing a file's modification time is possible
+add_task(async function test_file_modification_time() {
+ let file = do_get_profile();
+ file.append("testfile");
+
+ // Should never happen but get rid of it anyway
+ if (file.exists()) {
+ file.remove(true);
+ }
+
+ const now = Date.now();
+ file.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0o644);
+ Assert.ok(file.exists());
+
+ const atime = file.lastAccessedTime;
+
+ // Modification time may be out by up to 2 seconds on FAT filesystems. Test
+ // with a bit of leeway, close enough probably means it is correct.
+ let diff = Math.abs(file.lastModifiedTime - now);
+ Assert.ok(diff < MAX_TIME_DIFFERENCE);
+
+ const yesterday = now - MILLIS_PER_DAY;
+ file.lastModifiedTime = yesterday;
+
+ diff = Math.abs(file.lastModifiedTime - yesterday);
+ Assert.ok(diff < MAX_TIME_DIFFERENCE);
+ Assert.equal(
+ file.lastAccessedTime,
+ atime,
+ "Setting lastModifiedTime should not set lastAccessedTime"
+ );
+
+ const tomorrow = now + MILLIS_PER_DAY;
+ file.lastModifiedTime = tomorrow;
+
+ diff = Math.abs(file.lastModifiedTime - tomorrow);
+ Assert.ok(diff < MAX_TIME_DIFFERENCE);
+
+ const bug377307 = 1172950238000;
+ file.lastModifiedTime = bug377307;
+
+ diff = Math.abs(file.lastModifiedTime - bug377307);
+ Assert.ok(diff < MAX_TIME_DIFFERENCE);
+
+ await sleep(1000);
+
+ file.lastModifiedTime = 0;
+ Assert.greater(
+ file.lastModifiedTime,
+ now,
+ "Setting lastModifiedTime to 0 should set it to current date and time"
+ );
+
+ file.remove(true);
+});
+
+add_task(async function test_lastAccessedTime() {
+ const file = do_get_profile();
+
+ file.append("test-atime");
+ if (file.exists()) {
+ file.remove(true);
+ }
+
+ const now = Date.now();
+ file.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0o644);
+ Assert.ok(file.exists());
+
+ const mtime = file.lastModifiedTime;
+
+ // Modification time may be out by up to 2 seconds on FAT filesystems. Test
+ // with a bit of leeway, close enough probably means it is correct.
+ let diff = Math.abs(file.lastModifiedTime - now);
+ Assert.ok(diff < MAX_TIME_DIFFERENCE);
+
+ const yesterday = now - MILLIS_PER_DAY;
+ file.lastAccessedTime = yesterday;
+
+ diff = Math.abs(file.lastAccessedTime - yesterday);
+ Assert.ok(diff < MAX_TIME_DIFFERENCE, `${diff} < ${MAX_TIME_DIFFERENCE}`);
+ Assert.equal(
+ file.lastModifiedTime,
+ mtime,
+ "Setting lastAccessedTime should not set lastModifiedTime"
+ );
+
+ const tomorrow = now + MILLIS_PER_DAY;
+ file.lastAccessedTime = tomorrow;
+
+ diff = Math.abs(file.lastAccessedTime - tomorrow);
+ Assert.ok(diff < MAX_TIME_DIFFERENCE);
+
+ const bug377307 = 1172950238000;
+ file.lastAccessedTime = bug377307;
+
+ diff = Math.abs(file.lastAccessedTime - bug377307);
+ Assert.ok(diff < MAX_TIME_DIFFERENCE);
+
+ await sleep(1000);
+
+ file.lastAccessedTime = 0;
+ Assert.greater(
+ file.lastAccessedTime,
+ now,
+ "Setting lastAccessedTime to 0 should set it to the current date and time"
+ );
+});
+
+// Tests that changing a directory's modification time is possible
+add_task(function test_directory_modification_time() {
+ var dir = do_get_profile();
+ dir.append("testdir");
+
+ // Should never happen but get rid of it anyway
+ if (dir.exists()) {
+ dir.remove(true);
+ }
+
+ var now = Date.now();
+ dir.create(Ci.nsIFile.DIRECTORY_TYPE, 0o755);
+ Assert.ok(dir.exists());
+
+ // Modification time may be out by up to 2 seconds on FAT filesystems. Test
+ // with a bit of leeway, close enough probably means it is correct.
+ var diff = Math.abs(dir.lastModifiedTime - now);
+ Assert.ok(diff < MAX_TIME_DIFFERENCE);
+
+ var yesterday = now - MILLIS_PER_DAY;
+ dir.lastModifiedTime = yesterday;
+
+ diff = Math.abs(dir.lastModifiedTime - yesterday);
+ Assert.ok(diff < MAX_TIME_DIFFERENCE);
+
+ var tomorrow = now - MILLIS_PER_DAY;
+ dir.lastModifiedTime = tomorrow;
+
+ diff = Math.abs(dir.lastModifiedTime - tomorrow);
+ Assert.ok(diff < MAX_TIME_DIFFERENCE);
+
+ dir.remove(true);
+});
+
+add_task(function test_diskSpaceAvailable() {
+ let file = do_get_profile();
+ file.QueryInterface(Ci.nsIFile);
+
+ let bytes = file.diskSpaceAvailable;
+ Assert.ok(bytes > 0);
+
+ file.append("testfile");
+ if (file.exists()) {
+ file.remove(true);
+ }
+ file.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0o644);
+
+ bytes = file.diskSpaceAvailable;
+ Assert.ok(bytes > 0);
+
+ file.remove(true);
+});
+
+add_task(function test_diskCapacity() {
+ let file = do_get_profile();
+ file.QueryInterface(Ci.nsIFile);
+
+ const startBytes = file.diskCapacity;
+ Assert.ok(!!startBytes); // Not 0, undefined etc.
+
+ file.append("testfile");
+ if (file.exists()) {
+ file.remove(true);
+ }
+ file.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0o644);
+
+ const endBytes = file.diskCapacity;
+ Assert.ok(!!endBytes); // Not 0, undefined etc.
+ Assert.ok(startBytes === endBytes);
+
+ file.remove(true);
+});
+
+add_task(
+ {
+ // nsIFile::CreationTime is only supported on macOS and Windows.
+ skip_if: () => !["macosx", "win"].includes(AppConstants.platform),
+ },
+ function test_file_creation_time() {
+ const file = do_get_profile();
+ // If we re-use the same file name from the other tests, even if the
+ // file.exists() check fails at 165, this test will likely fail due to the
+ // creation time being copied over from the previous instance of the file on
+ // Windows.
+ file.append("testfile-creation-time");
+
+ if (file.exists()) {
+ file.remove(true);
+ }
+
+ const now = Date.now();
+
+ file.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0o644);
+ Assert.ok(file.exists());
+
+ const creationTime = file.creationTime;
+ Assert.ok(creationTime === file.lastModifiedTime);
+
+ file.lastModifiedTime = now + MILLIS_PER_DAY;
+
+ Assert.ok(creationTime !== file.lastModifiedTime);
+ Assert.ok(creationTime === file.creationTime);
+
+ file.remove(true);
+ }
+);
+
+add_task(function test_file_append_parent() {
+ const SEPARATOR = AppConstants.platform === "win" ? "\\" : "/";
+
+ const file = do_get_profile();
+
+ Assert.throws(
+ () => file.append(".."),
+ /NS_ERROR_FILE_UNRECOGNIZED_PATH/,
+ `nsLocalFile::Append("..") throws`
+ );
+
+ Assert.throws(
+ () => file.appendRelativePath(".."),
+ /NS_ERROR_FILE_UNRECOGNIZED_PATH/,
+ `nsLocalFile::AppendRelativePath("..") throws`
+ );
+
+ Assert.throws(
+ () => file.appendRelativePath(`foo${SEPARATOR}..${SEPARATOR}baz`),
+ /NS_ERROR_FILE_UNRECOGNIZED_PATH/,
+ `nsLocalFile::AppendRelativePath(path) fails when path contains ".."`
+ );
+});
diff --git a/xpcom/tests/unit/test_mac_bundle.js b/xpcom/tests/unit/test_mac_bundle.js
new file mode 100644
index 0000000000..6703e8a2b8
--- /dev/null
+++ b/xpcom/tests/unit/test_mac_bundle.js
@@ -0,0 +1,18 @@
+function run_test() {
+ // this is a hack to skip the rest of the code on non-Mac platforms,
+ // since #ifdef is not available to xpcshell tests...
+ if (mozinfo.os != "mac") {
+ return;
+ }
+
+ // OK, here's the real part of the test:
+ // make sure these two test bundles are recognized as bundles (or "packages")
+ var keynoteBundle = do_get_file("data/presentation.key");
+ var appBundle = do_get_file("data/SmallApp.app");
+
+ Assert.ok(keynoteBundle instanceof Ci.nsILocalFileMac);
+ Assert.ok(appBundle instanceof Ci.nsILocalFileMac);
+
+ Assert.ok(keynoteBundle.isPackage());
+ Assert.ok(appBundle.isPackage());
+}
diff --git a/xpcom/tests/unit/test_mac_xattrs.js b/xpcom/tests/unit/test_mac_xattrs.js
new file mode 100644
index 0000000000..b387358d74
--- /dev/null
+++ b/xpcom/tests/unit/test_mac_xattrs.js
@@ -0,0 +1,98 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+const { FileUtils } = ChromeUtils.importESModule(
+ "resource://gre/modules/FileUtils.sys.mjs"
+);
+
+const ATTR = "bogus.attr";
+const VALUE = new TextEncoder().encode("bogus");
+
+async function run_test() {
+ const path = PathUtils.join(
+ Services.dirsvc.get("TmpD", Ci.nsIFile).path,
+ "macos-xattrs.tmp.d"
+ );
+ await IOUtils.makeDirectory(path);
+
+ try {
+ await test_macos_xattr(path);
+ } finally {
+ await IOUtils.remove(path, { recursive: true });
+ }
+}
+
+async function test_macos_xattr(tmpDir) {
+ const path = PathUtils.join(tmpDir, "file.tmp");
+
+ await IOUtils.writeUTF8(path, "");
+
+ const file = new FileUtils.File(path);
+ file.queryInterface(Cc.nsILocalFileMac);
+
+ Assert.ok(!file.exists(), "File should not exist");
+
+ info("Testing reading an attribute on a file that does not exist");
+ Assert.throws(
+ () => file.hasXAttr(ATTR),
+ /NS_ERROR_FILE_NOT_FOUND/,
+ "Non-existant files can't have attributes checked"
+ );
+ Assert.throws(
+ () => file.getXAttr(ATTR),
+ /NS_ERROR_FILE_NOT_FOUND/,
+ "Non-existant files can't have attributes read"
+ );
+
+ file.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0o644);
+ Assert.ok(file.exists(), "File exists after creation");
+
+ info("Testing reading an attribute that does not exist");
+ Assert.ok(
+ !file.hasXAttr(ATTR),
+ "File should not have attribute before being set."
+ );
+ Assert.throws(
+ () => file.getXAttr(ATTR),
+ /NS_ERROR_NOT_AVAILABLE/,
+ "Attempting to get an attribute that does not exist throws"
+ );
+
+ {
+ info("Testing setting and reading an attribute");
+ file.setXAttr(ATTR, VALUE);
+ Assert.ok(
+ file.hasXAttr(ATTR),
+ "File should have attribute after being set"
+ );
+ const result = file.getXAttr(ATTR);
+
+ Assert.deepEqual(
+ Array.from(result),
+ Array.from(VALUE),
+ "File should have attribute value matching what was set"
+ );
+ }
+
+ info("Testing removing an attribute");
+ file.delXAttr(ATTR);
+ Assert.ok(
+ !file.hasXAttr(ATTR),
+ "File should no longer have the attribute after removal"
+ );
+ Assert.throws(
+ () => file.getXAttr(ATTR),
+ /NS_ERROR_NOT_AVAILABLE/,
+ "Attempting to get an attribute after removal results in an error"
+ );
+
+ info("Testing removing an attribute that does not exist");
+ Assert.throws(
+ () => file.delXAttr(ATTR),
+ /NS_ERROR_NOT_AVAILABLE/,
+ "Attempting to remove an attribute that does not exist throws"
+ );
+}
diff --git a/xpcom/tests/unit/test_notxpcom_scriptable.js b/xpcom/tests/unit/test_notxpcom_scriptable.js
new file mode 100644
index 0000000000..5362894b70
--- /dev/null
+++ b/xpcom/tests/unit/test_notxpcom_scriptable.js
@@ -0,0 +1,67 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+const kCID = Components.ID("{1f9f7181-e6c5-4f4c-8f71-08005cec8468}");
+const kContract = "@testing/notxpcomtest";
+
+function run_test() {
+ let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
+
+ ok(Ci.nsIScriptableWithNotXPCOM);
+
+ let method1Called = false;
+
+ let testObject = {
+ QueryInterface: ChromeUtils.generateQI([
+ "nsIScriptableOK",
+ "nsIScriptableWithNotXPCOM",
+ ]),
+
+ method1() {
+ method1Called = true;
+ },
+
+ method2() {
+ ok(false, "method2 should not have been called!");
+ },
+
+ method3() {
+ ok(false, "mehod3 should not have been called!");
+ },
+
+ jsonly: true,
+ };
+
+ let factory = {
+ QueryInterface: ChromeUtils.generateQI(["nsIFactory"]),
+
+ createInstance(iid) {
+ return testObject.QueryInterface(iid);
+ },
+ };
+
+ registrar.registerFactory(kCID, null, kContract, factory);
+
+ let xpcomObject = Cc[kContract].createInstance();
+ ok(xpcomObject);
+ strictEqual(xpcomObject.jsonly, undefined);
+
+ xpcomObject.QueryInterface(Ci.nsIScriptableOK);
+
+ xpcomObject.method1();
+ ok(method1Called);
+
+ try {
+ xpcomObject.QueryInterface(Ci.nsIScriptableWithNotXPCOM);
+ ok(false, "Should not have implemented nsIScriptableWithNotXPCOM");
+ } catch (e) {
+ ok(
+ true,
+ "Should not have implemented nsIScriptableWithNotXPCOM. Correctly threw error: " +
+ e
+ );
+ }
+ strictEqual(xpcomObject.method2, undefined);
+}
diff --git a/xpcom/tests/unit/test_nsIMutableArray.js b/xpcom/tests/unit/test_nsIMutableArray.js
new file mode 100644
index 0000000000..525196a48f
--- /dev/null
+++ b/xpcom/tests/unit/test_nsIMutableArray.js
@@ -0,0 +1,131 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+var MutableArray = CC("@mozilla.org/array;1", "nsIMutableArray");
+var SupportsString = CC("@mozilla.org/supports-string;1", "nsISupportsString");
+
+function create_n_element_array(n) {
+ var arr = new MutableArray();
+ for (let i = 0; i < n; i++) {
+ let str = new SupportsString();
+ str.data = "element " + i;
+ arr.appendElement(str);
+ }
+ return arr;
+}
+
+function test_appending_null_actually_inserts() {
+ var arr = new MutableArray();
+ Assert.equal(0, arr.length);
+ arr.appendElement(null);
+ Assert.equal(1, arr.length);
+}
+
+function test_object_gets_appended() {
+ var arr = new MutableArray();
+ var str = new SupportsString();
+ str.data = "hello";
+ arr.appendElement(str);
+ Assert.equal(1, arr.length);
+ var obj = arr.queryElementAt(0, Ci.nsISupportsString);
+ Assert.equal(str, obj);
+}
+
+function test_insert_at_beginning() {
+ var arr = create_n_element_array(5);
+ // just a sanity check
+ Assert.equal(5, arr.length);
+ var str = new SupportsString();
+ str.data = "hello";
+ arr.insertElementAt(str, 0);
+ Assert.equal(6, arr.length);
+ var obj = arr.queryElementAt(0, Ci.nsISupportsString);
+ Assert.equal(str, obj);
+ // check the data of all the other objects
+ for (let i = 1; i < arr.length; i++) {
+ let obj2 = arr.queryElementAt(i, Ci.nsISupportsString);
+ Assert.equal("element " + (i - 1), obj2.data);
+ }
+}
+
+function test_replace_element() {
+ var arr = create_n_element_array(5);
+ // just a sanity check
+ Assert.equal(5, arr.length);
+ var str = new SupportsString();
+ str.data = "hello";
+ // replace first element
+ arr.replaceElementAt(str, 0);
+ Assert.equal(5, arr.length);
+ var obj = arr.queryElementAt(0, Ci.nsISupportsString);
+ Assert.equal(str, obj);
+ // replace last element
+ arr.replaceElementAt(str, arr.length - 1);
+ Assert.equal(5, arr.length);
+ obj = arr.queryElementAt(arr.length - 1, Ci.nsISupportsString);
+ Assert.equal(str, obj);
+ // replace after last element, should insert empty elements
+ arr.replaceElementAt(str, 9);
+ Assert.equal(10, arr.length);
+ obj = arr.queryElementAt(9, Ci.nsISupportsString);
+ Assert.equal(str, obj);
+ // AFAIK there's no way to check the empty elements, since you can't QI them.
+}
+
+function test_clear() {
+ var arr = create_n_element_array(5);
+ // just a sanity check
+ Assert.equal(5, arr.length);
+ arr.clear();
+ Assert.equal(0, arr.length);
+}
+
+function test_enumerate() {
+ var arr = create_n_element_array(5);
+ Assert.equal(5, arr.length);
+ var i = 0;
+ for (let str of arr.enumerate()) {
+ Assert.ok(str instanceof Ci.nsISupportsString);
+ Assert.equal(str.data, "element " + i);
+ i++;
+ }
+ Assert.equal(arr.length, i);
+}
+
+function test_nsiarrayextensions() {
+ // Tests to check that the extensions that make an nsArray act like an
+ // nsISupportsArray for iteration purposes works.
+ // Note: we do not want to QI here, just want to make sure the magic glue
+ // works as a drop-in replacement.
+
+ let fake_nsisupports_array = create_n_element_array(5);
+
+ // Check that |Count| works.
+ Assert.equal(5, fake_nsisupports_array.Count());
+
+ for (let i = 0; i < fake_nsisupports_array.Count(); i++) {
+ // Check that the generic |GetElementAt| works.
+ let elm = fake_nsisupports_array.GetElementAt(i);
+ Assert.notEqual(elm, null);
+ let str = elm.QueryInterface(Ci.nsISupportsString);
+ Assert.notEqual(str, null);
+ Assert.equal(str.data, "element " + i);
+ }
+}
+
+var tests = [
+ test_appending_null_actually_inserts,
+ test_object_gets_appended,
+ test_insert_at_beginning,
+ test_replace_element,
+ test_clear,
+ test_enumerate,
+ test_nsiarrayextensions,
+];
+
+function run_test() {
+ for (var i = 0; i < tests.length; i++) {
+ tests[i]();
+ }
+}
diff --git a/xpcom/tests/unit/test_nsIProcess.js b/xpcom/tests/unit/test_nsIProcess.js
new file mode 100644
index 0000000000..582d10440c
--- /dev/null
+++ b/xpcom/tests/unit/test_nsIProcess.js
@@ -0,0 +1,184 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+// nsIProcess unit test
+const TEST_ARGS = [
+ "mozilla",
+ "firefox",
+ "thunderbird",
+ "seamonkey",
+ "foo",
+ "bar",
+ "argument with spaces",
+ '"argument with quotes"',
+];
+
+const TEST_UNICODE_ARGS = [
+ "M\u00F8z\u00EEll\u00E5",
+ "\u041C\u043E\u0437\u0438\u043B\u043B\u0430",
+ "\u09AE\u09CB\u099C\u09BF\u09B2\u09BE",
+ "\uD808\uDE2C\uD808\uDF63\uD808\uDDB7",
+];
+
+// test if a process can be started, polled for its running status
+// and then killed
+function test_kill() {
+ var file = get_test_program("TestBlockingProcess");
+
+ var process = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess);
+ process.init(file);
+
+ Assert.ok(!process.isRunning);
+
+ try {
+ process.kill();
+ do_throw("Attempting to kill a not-running process should throw");
+ } catch (e) {}
+
+ process.run(false, [], 0);
+
+ Assert.ok(process.isRunning);
+
+ process.kill();
+
+ Assert.ok(!process.isRunning);
+
+ try {
+ process.kill();
+ do_throw("Attempting to kill a not-running process should throw");
+ } catch (e) {}
+}
+
+// test if we can get an exit value from an application that is
+// guaranteed to return an exit value of 42
+function test_quick() {
+ var file = get_test_program("TestQuickReturn");
+
+ var process = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess);
+ process.init(file);
+
+ // to get an exit value it must be a blocking process
+ process.run(true, [], 0);
+
+ Assert.equal(process.exitValue, 42);
+}
+
+function test_args(file, args, argsAreASCII) {
+ var process = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess);
+ process.init(file);
+
+ if (argsAreASCII) {
+ process.run(true, args, args.length);
+ } else {
+ process.runw(true, args, args.length);
+ }
+
+ Assert.equal(process.exitValue, 0);
+}
+
+// test if an argument can be successfully passed to an application
+// that will return 0 if "mozilla" is the only argument
+function test_arguments() {
+ test_args(get_test_program("TestArguments"), TEST_ARGS, true);
+}
+
+// test if Unicode arguments can be successfully passed to an application
+function test_unicode_arguments() {
+ test_args(get_test_program("TestUnicodeArguments"), TEST_UNICODE_ARGS, false);
+}
+
+function rename_and_test(asciiName, unicodeName, args, argsAreASCII) {
+ var asciiFile = get_test_program(asciiName);
+ var asciiLeaf = asciiFile.leafName;
+ var unicodeLeaf = asciiLeaf.replace(asciiName, unicodeName);
+
+ asciiFile.moveTo(null, unicodeLeaf);
+
+ var unicodeFile = get_test_program(unicodeName);
+
+ test_args(unicodeFile, args, argsAreASCII);
+
+ unicodeFile.moveTo(null, asciiLeaf);
+}
+
+// test passing ASCII and Unicode arguments to an application with a Unicode name
+function test_unicode_app() {
+ rename_and_test(
+ "TestArguments",
+ // "Unicode" in Tamil
+ "\u0BAF\u0BC1\u0BA9\u0BBF\u0B95\u0BCB\u0B9F\u0BCD",
+ TEST_ARGS,
+ true
+ );
+
+ rename_and_test(
+ "TestUnicodeArguments",
+ // "Unicode" in Thai
+ "\u0E22\u0E39\u0E19\u0E34\u0E42\u0E04\u0E14",
+ TEST_UNICODE_ARGS,
+ false
+ );
+}
+
+// test if we get notified about a blocking process
+function test_notify_blocking() {
+ var file = get_test_program("TestQuickReturn");
+
+ var process = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess);
+ process.init(file);
+
+ process.runAsync([], 0, {
+ observe(subject, topic, data) {
+ process = subject.QueryInterface(Ci.nsIProcess);
+ Assert.equal(topic, "process-failed");
+ Assert.equal(process.exitValue, 42);
+ test_notify_nonblocking();
+ },
+ });
+}
+
+// test if we get notified about a non-blocking process
+function test_notify_nonblocking() {
+ var file = get_test_program("TestArguments");
+
+ var process = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess);
+ process.init(file);
+
+ process.runAsync(TEST_ARGS, TEST_ARGS.length, {
+ observe(subject, topic, data) {
+ process = subject.QueryInterface(Ci.nsIProcess);
+ Assert.equal(topic, "process-finished");
+ Assert.equal(process.exitValue, 0);
+ test_notify_killed();
+ },
+ });
+}
+
+// test if we get notified about a killed process
+function test_notify_killed() {
+ var file = get_test_program("TestBlockingProcess");
+
+ var process = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess);
+ process.init(file);
+
+ process.runAsync([], 0, {
+ observe(subject, topic, data) {
+ process = subject.QueryInterface(Ci.nsIProcess);
+ Assert.equal(topic, "process-failed");
+ do_test_finished();
+ },
+ });
+
+ process.kill();
+}
+
+function run_test() {
+ set_process_running_environment();
+ test_kill();
+ test_quick();
+ test_arguments();
+ test_unicode_arguments();
+ test_unicode_app();
+ do_test_pending();
+ test_notify_blocking();
+}
diff --git a/xpcom/tests/unit/test_nsIProcess_stress.js b/xpcom/tests/unit/test_nsIProcess_stress.js
new file mode 100644
index 0000000000..802f9d70aa
--- /dev/null
+++ b/xpcom/tests/unit/test_nsIProcess_stress.js
@@ -0,0 +1,24 @@
+function run_test() {
+ set_process_running_environment();
+
+ var file = get_test_program("TestQuickReturn");
+ var tm = Cc["@mozilla.org/thread-manager;1"].getService();
+
+ for (var i = 0; i < 1000; i++) {
+ var process = Cc["@mozilla.org/process/util;1"].createInstance(
+ Ci.nsIProcess
+ );
+ process.init(file);
+
+ process.run(false, [], 0);
+
+ try {
+ process.kill();
+ } catch (e) {}
+
+ // We need to ensure that we process any events on the main thread -
+ // this allow threads to clean up properly and avoid out of memory
+ // errors during the test.
+ tm.spinEventLoopUntilEmpty();
+ }
+}
diff --git a/xpcom/tests/unit/test_pipe.js b/xpcom/tests/unit/test_pipe.js
new file mode 100644
index 0000000000..e3ccc6ef3f
--- /dev/null
+++ b/xpcom/tests/unit/test_pipe.js
@@ -0,0 +1,55 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+var Pipe = CC("@mozilla.org/pipe;1", "nsIPipe", "init");
+
+function run_test() {
+ test_not_initialized();
+ test_ends_are_threadsafe();
+}
+
+function test_not_initialized() {
+ var p = Cc["@mozilla.org/pipe;1"].createInstance(Ci.nsIPipe);
+ try {
+ var dummy = p.outputStream;
+ dump("dummy: " + dummy + "\n");
+ throw Components.Exception("", Cr.NS_ERROR_FAILURE);
+ } catch (e) {
+ if (e.result != Cr.NS_ERROR_NOT_INITIALIZED) {
+ do_throw(
+ "using a pipe before initializing it should throw NS_ERROR_NOT_INITIALIZED"
+ );
+ }
+ }
+}
+
+function test_ends_are_threadsafe() {
+ var p, is, os;
+
+ p = new Pipe(true, true, 1024, 1, null);
+ is = p.inputStream.QueryInterface(Ci.nsIClassInfo);
+ os = p.outputStream.QueryInterface(Ci.nsIClassInfo);
+ Assert.ok(Boolean(is.flags & Ci.nsIClassInfo.THREADSAFE));
+ Assert.ok(Boolean(os.flags & Ci.nsIClassInfo.THREADSAFE));
+
+ p = new Pipe(true, false, 1024, 1, null);
+ is = p.inputStream.QueryInterface(Ci.nsIClassInfo);
+ os = p.outputStream.QueryInterface(Ci.nsIClassInfo);
+ Assert.ok(Boolean(is.flags & Ci.nsIClassInfo.THREADSAFE));
+ Assert.ok(Boolean(os.flags & Ci.nsIClassInfo.THREADSAFE));
+
+ p = new Pipe(false, true, 1024, 1, null);
+ is = p.inputStream.QueryInterface(Ci.nsIClassInfo);
+ os = p.outputStream.QueryInterface(Ci.nsIClassInfo);
+ Assert.ok(Boolean(is.flags & Ci.nsIClassInfo.THREADSAFE));
+ Assert.ok(Boolean(os.flags & Ci.nsIClassInfo.THREADSAFE));
+
+ p = new Pipe(false, false, 1024, 1, null);
+ is = p.inputStream.QueryInterface(Ci.nsIClassInfo);
+ os = p.outputStream.QueryInterface(Ci.nsIClassInfo);
+ Assert.ok(Boolean(is.flags & Ci.nsIClassInfo.THREADSAFE));
+ Assert.ok(Boolean(os.flags & Ci.nsIClassInfo.THREADSAFE));
+}
diff --git a/xpcom/tests/unit/test_process_directives.js b/xpcom/tests/unit/test_process_directives.js
new file mode 100644
index 0000000000..b1975a43da
--- /dev/null
+++ b/xpcom/tests/unit/test_process_directives.js
@@ -0,0 +1,20 @@
+function categoryExists(category, entry) {
+ try {
+ Services.catMan.getCategoryEntry(category, entry);
+ return true;
+ } catch (e) {
+ return false;
+ }
+}
+
+function run_test() {
+ Components.manager.autoRegister(
+ do_get_file("data/process_directive.manifest")
+ );
+
+ let isChild =
+ Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT;
+
+ Assert.equal(categoryExists("directives-test", "main-process"), !isChild);
+ Assert.equal(categoryExists("directives-test", "content-process"), isChild);
+}
diff --git a/xpcom/tests/unit/test_process_directives_child.js b/xpcom/tests/unit/test_process_directives_child.js
new file mode 100644
index 0000000000..dca63b3563
--- /dev/null
+++ b/xpcom/tests/unit/test_process_directives_child.js
@@ -0,0 +1,3 @@
+function run_test() {
+ run_test_in_child("test_process_directives.js");
+}
diff --git a/xpcom/tests/unit/test_seek_multiplex.js b/xpcom/tests/unit/test_seek_multiplex.js
new file mode 100644
index 0000000000..7a469d9f48
--- /dev/null
+++ b/xpcom/tests/unit/test_seek_multiplex.js
@@ -0,0 +1,164 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// The string we use as data.
+const data = "0123456789";
+// Number of streams in the multiplex stream.
+const count = 10;
+
+function test_multiplex_streams() {
+ var MultiplexStream = CC(
+ "@mozilla.org/io/multiplex-input-stream;1",
+ "nsIMultiplexInputStream"
+ );
+ Assert.equal(1, 1);
+
+ var multiplex = new MultiplexStream();
+ for (var i = 0; i < count; ++i) {
+ let s = Cc["@mozilla.org/io/string-input-stream;1"].createInstance(
+ Ci.nsIStringInputStream
+ );
+ s.setData(data, data.length);
+
+ multiplex.appendStream(s);
+ }
+ var seekable = multiplex.QueryInterface(Ci.nsISeekableStream);
+ var sis = Cc["@mozilla.org/scriptableinputstream;1"].createInstance(
+ Ci.nsIScriptableInputStream
+ );
+ sis.init(seekable);
+ // Read some data.
+ var readData = sis.read(20);
+ Assert.equal(readData, data + data);
+ // -- Tests for NS_SEEK_SET
+ // Seek to a non-zero, non-stream-boundary offset.
+ seekable.seek(Ci.nsISeekableStream.NS_SEEK_SET, 2);
+ Assert.equal(seekable.tell(), 2);
+ Assert.equal(seekable.available(), 98);
+ seekable.seek(Ci.nsISeekableStream.NS_SEEK_SET, 9);
+ Assert.equal(seekable.tell(), 9);
+ Assert.equal(seekable.available(), 91);
+ // Seek across stream boundary.
+ seekable.seek(Ci.nsISeekableStream.NS_SEEK_SET, 35);
+ Assert.equal(seekable.tell(), 35);
+ Assert.equal(seekable.available(), 65);
+ readData = sis.read(5);
+ Assert.equal(readData, data.slice(5));
+ Assert.equal(seekable.available(), 60);
+ // Seek at stream boundaries.
+ seekable.seek(Ci.nsISeekableStream.NS_SEEK_SET, 40);
+ Assert.equal(seekable.tell(), 40);
+ Assert.equal(seekable.available(), 60);
+ readData = sis.read(10);
+ Assert.equal(readData, data);
+ Assert.equal(seekable.tell(), 50);
+ Assert.equal(seekable.available(), 50);
+ // Rewind and read across streams.
+ seekable.seek(Ci.nsISeekableStream.NS_SEEK_SET, 39);
+ Assert.equal(seekable.tell(), 39);
+ Assert.equal(seekable.available(), 61);
+ readData = sis.read(11);
+ Assert.equal(readData, data.slice(9) + data);
+ Assert.equal(seekable.tell(), 50);
+ Assert.equal(seekable.available(), 50);
+ // Rewind to the beginning.
+ seekable.seek(Ci.nsISeekableStream.NS_SEEK_SET, 0);
+ Assert.equal(seekable.tell(), 0);
+ Assert.equal(seekable.available(), 100);
+ // Seek to some random location
+ seekable.seek(Ci.nsISeekableStream.NS_SEEK_SET, 50);
+ // -- Tests for NS_SEEK_CUR
+ // Positive seek.
+ seekable.seek(Ci.nsISeekableStream.NS_SEEK_CUR, 15);
+ Assert.equal(seekable.tell(), 65);
+ Assert.equal(seekable.available(), 35);
+ readData = sis.read(10);
+ Assert.equal(readData, data.slice(5) + data.slice(0, 5));
+ Assert.equal(seekable.tell(), 75);
+ Assert.equal(seekable.available(), 25);
+ // Negative seek.
+ seekable.seek(Ci.nsISeekableStream.NS_SEEK_CUR, -15);
+ Assert.equal(seekable.tell(), 60);
+ Assert.equal(seekable.available(), 40);
+ readData = sis.read(10);
+ Assert.equal(readData, data);
+ Assert.equal(seekable.tell(), 70);
+ Assert.equal(seekable.available(), 30);
+
+ // -- Tests for NS_SEEK_END
+ // Normal read.
+ seekable.seek(Ci.nsISeekableStream.NS_SEEK_END, -5);
+ Assert.equal(seekable.tell(), data.length * count - 5);
+ readData = sis.read(5);
+ Assert.equal(readData, data.slice(5));
+ Assert.equal(seekable.tell(), data.length * count);
+ // Read across streams.
+ seekable.seek(Ci.nsISeekableStream.NS_SEEK_END, -15);
+ Assert.equal(seekable.tell(), data.length * count - 15);
+ readData = sis.read(15);
+ Assert.equal(readData, data.slice(5) + data);
+ Assert.equal(seekable.tell(), data.length * count);
+
+ // -- Try to do various edge cases
+ // Forward seek from the end, should throw.
+ var caught = false;
+ try {
+ seekable.seek(Ci.nsISeekableStream.NS_SEEK_END, 15);
+ } catch (e) {
+ caught = true;
+ }
+ Assert.equal(caught, true);
+ Assert.equal(seekable.tell(), data.length * count);
+ // Backward seek from the beginning, should be clamped.
+ seekable.seek(Ci.nsISeekableStream.NS_SEEK_SET, 0);
+ Assert.equal(seekable.tell(), 0);
+ seekable.seek(Ci.nsISeekableStream.NS_SEEK_CUR, -15);
+ Assert.equal(seekable.tell(), 0);
+ // Seek too far: should be clamped.
+ seekable.seek(Ci.nsISeekableStream.NS_SEEK_SET, 0);
+ Assert.equal(seekable.tell(), 0);
+ seekable.seek(Ci.nsISeekableStream.NS_SEEK_CUR, 3 * data.length * count);
+ Assert.equal(seekable.tell(), 100);
+ seekable.seek(Ci.nsISeekableStream.NS_SEEK_SET, data.length * count);
+ Assert.equal(seekable.tell(), 100);
+ seekable.seek(Ci.nsISeekableStream.NS_SEEK_CUR, -2 * data.length * count);
+ Assert.equal(seekable.tell(), 0);
+}
+
+function test_multiplex_bug797871() {
+ var data2 = "1234567890123456789012345678901234567890";
+
+ var MultiplexStream = CC(
+ "@mozilla.org/io/multiplex-input-stream;1",
+ "nsIMultiplexInputStream"
+ );
+ Assert.equal(1, 1);
+
+ var multiplex = new MultiplexStream();
+ let s = Cc["@mozilla.org/io/string-input-stream;1"].createInstance(
+ Ci.nsIStringInputStream
+ );
+ s.setData(data2, data2.length);
+
+ multiplex.appendStream(s);
+
+ var seekable = multiplex.QueryInterface(Ci.nsISeekableStream);
+ var sis = Cc["@mozilla.org/scriptableinputstream;1"].createInstance(
+ Ci.nsIScriptableInputStream
+ );
+ sis.init(seekable);
+
+ seekable.seek(Ci.nsISeekableStream.NS_SEEK_SET, 8);
+ Assert.equal(seekable.tell(), 8);
+ sis.read(2);
+ Assert.equal(seekable.tell(), 10);
+
+ seekable.seek(Ci.nsISeekableStream.NS_SEEK_SET, 20);
+ Assert.equal(seekable.tell(), 20);
+}
+
+function run_test() {
+ test_multiplex_streams();
+ test_multiplex_bug797871();
+}
diff --git a/xpcom/tests/unit/test_storagestream.js b/xpcom/tests/unit/test_storagestream.js
new file mode 100644
index 0000000000..2a0fb1b569
--- /dev/null
+++ b/xpcom/tests/unit/test_storagestream.js
@@ -0,0 +1,152 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* eslint no-unused-vars: ["error", { "varsIgnorePattern": "unusedVariable" }] */
+
+function run_test() {
+ test1();
+ test2();
+ test3();
+ test4();
+}
+
+/**
+ * Checks that getting an input stream from a storage stream which has never had
+ * anything written to it throws a not-initialized exception.
+ */
+function test1() {
+ var ss = Cc["@mozilla.org/storagestream;1"].createInstance(
+ Ci.nsIStorageStream
+ );
+ ss.init(1024, 1024, null);
+
+ var unusedVariable = ss.getOutputStream(0);
+ var inp2 = ss.newInputStream(0);
+ Assert.equal(inp2.available(), 0);
+ Assert.ok(inp2.isNonBlocking());
+
+ var sis = Cc["@mozilla.org/scriptableinputstream;1"].createInstance(
+ Ci.nsIScriptableInputStream
+ );
+ sis.init(inp2);
+
+ var threw = false;
+ try {
+ sis.read(1);
+ } catch (ex) {
+ if (ex.result == Cr.NS_BASE_STREAM_WOULD_BLOCK) {
+ threw = true;
+ } else {
+ throw ex;
+ }
+ }
+ Assert.ok(threw);
+}
+
+/**
+ * Checks that getting an input stream from a storage stream to which 0 bytes of
+ * data have been explicitly written doesn't throw an exception.
+ */
+function test2() {
+ var ss = Cc["@mozilla.org/storagestream;1"].createInstance(
+ Ci.nsIStorageStream
+ );
+ ss.init(1024, 1024, null);
+
+ var out = ss.getOutputStream(0);
+ out.write("", 0);
+ try {
+ ss.newInputStream(0);
+ } catch (e) {
+ do_throw("shouldn't throw exception when new input stream created");
+ }
+}
+
+/**
+ * Checks that reading any non-zero amount of data from a storage stream
+ * which has had 0 bytes written to it explicitly works correctly.
+ */
+function test3() {
+ var ss = Cc["@mozilla.org/storagestream;1"].createInstance(
+ Ci.nsIStorageStream
+ );
+ ss.init(1024, 1024, null);
+
+ var out = ss.getOutputStream(0);
+ out.write("", 0);
+ try {
+ var inp = ss.newInputStream(0);
+ } catch (e) {
+ do_throw("newInputStream(0) shouldn't throw if write() is called: " + e);
+ }
+
+ Assert.ok(inp.isNonBlocking(), "next test expects a non-blocking stream");
+
+ try {
+ var threw = false;
+ var bis = BIS(inp);
+ bis.readByteArray(5);
+ } catch (e) {
+ if (e.result != Cr.NS_BASE_STREAM_WOULD_BLOCK) {
+ do_throw("wrong error thrown: " + e);
+ }
+ threw = true;
+ }
+ Assert.ok(threw, "should have thrown (nsStorageInputStream is nonblocking)");
+}
+
+/**
+ * Basic functionality test for storagestream: write data to it, get an input
+ * stream, and read the data back to see that it matches.
+ */
+function test4() {
+ var bytes = [65, 66, 67, 68, 69, 70, 71, 72, 73, 74];
+
+ var ss = Cc["@mozilla.org/storagestream;1"].createInstance(
+ Ci.nsIStorageStream
+ );
+ ss.init(1024, 1024, null);
+
+ var outStream = ss.getOutputStream(0);
+
+ var bos = Cc["@mozilla.org/binaryoutputstream;1"].createInstance(
+ Ci.nsIBinaryOutputStream
+ );
+ bos.setOutputStream(outStream);
+
+ bos.writeByteArray(bytes);
+ bos.close();
+
+ var inp = ss.newInputStream(0);
+ var bis = BIS(inp);
+
+ var count = 0;
+ while (count < bytes.length) {
+ var data = bis.read8(1);
+ Assert.equal(data, bytes[count++]);
+ }
+
+ var threw = false;
+ try {
+ data = bis.read8(1);
+ } catch (e) {
+ if (e.result != Cr.NS_ERROR_FAILURE) {
+ do_throw("wrong error thrown: " + e);
+ }
+ threw = true;
+ }
+ if (!threw) {
+ do_throw("should have thrown but instead returned: '" + data + "'");
+ }
+}
+
+function BIS(input) {
+ var bis = Cc["@mozilla.org/binaryinputstream;1"].createInstance(
+ Ci.nsIBinaryInputStream
+ );
+ bis.setInputStream(input);
+ return bis;
+}
diff --git a/xpcom/tests/unit/test_streams.js b/xpcom/tests/unit/test_streams.js
new file mode 100644
index 0000000000..212b41cc8e
--- /dev/null
+++ b/xpcom/tests/unit/test_streams.js
@@ -0,0 +1,170 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+var Pipe = CC("@mozilla.org/pipe;1", "nsIPipe", "init");
+var BinaryOutput = CC(
+ "@mozilla.org/binaryoutputstream;1",
+ "nsIBinaryOutputStream",
+ "setOutputStream"
+);
+var BinaryInput = CC(
+ "@mozilla.org/binaryinputstream;1",
+ "nsIBinaryInputStream",
+ "setInputStream"
+);
+
+/**
+ * Binary stream tests.
+ */
+function test_binary_streams() {
+ var p, is, os;
+
+ p = new Pipe(false, false, 1024, 1, null);
+ is = new BinaryInput(p.inputStream);
+ os = new BinaryOutput(p.outputStream);
+
+ const LargeNum = Math.pow(2, 18) + Math.pow(2, 12) + 1;
+ const HugeNum = Math.pow(2, 62);
+ const HelloStr = "Hello World";
+ const HelloArray = Array.from(HelloStr, function(c) {
+ return c.charCodeAt(0);
+ });
+ var countObj = {};
+ var msg = {};
+ var buffer = new ArrayBuffer(HelloArray.length);
+
+ // Test reading immediately after writing.
+ os.writeBoolean(true);
+ Assert.equal(is.readBoolean(), true);
+ os.write8(4);
+ Assert.equal(is.read8(), 4);
+ os.write16(4);
+ Assert.equal(is.read16(), 4);
+ os.write16(1024);
+ Assert.equal(is.read16(), 1024);
+ os.write32(7);
+ Assert.equal(is.read32(), 7);
+ os.write32(LargeNum);
+ Assert.equal(is.read32(), LargeNum);
+ os.write64(LargeNum);
+ Assert.equal(is.read64(), LargeNum);
+ os.write64(1024);
+ Assert.equal(is.read64(), 1024);
+ os.write64(HugeNum);
+ Assert.equal(is.read64(), HugeNum);
+ os.writeFloat(2.5);
+ Assert.equal(is.readFloat(), 2.5);
+ // os.writeDouble(Math.SQRT2);
+ // do_check_eq(is.readDouble(), Math.SQRT2);
+ os.writeStringZ("Mozilla");
+ Assert.equal(is.readCString(), "Mozilla");
+ os.writeWStringZ("Gecko");
+ Assert.equal(is.readString(), "Gecko");
+ os.writeBytes(HelloStr, HelloStr.length);
+ Assert.equal(is.available(), HelloStr.length);
+ msg = is.readBytes(HelloStr.length);
+ Assert.equal(msg, HelloStr);
+ msg = null;
+ countObj.value = -1;
+ os.writeByteArray(HelloArray);
+ Assert.equal(is.available(), HelloStr.length);
+ msg = is.readByteArray(HelloStr.length);
+ Assert.equal(typeof msg, typeof HelloArray);
+ Assert.equal(msg.toSource(), HelloArray.toSource());
+ Assert.equal(is.available(), 0);
+ os.writeByteArray(HelloArray);
+ Assert.equal(
+ is.readArrayBuffer(buffer.byteLength, buffer),
+ HelloArray.length
+ );
+ Assert.equal([...new Uint8Array(buffer)].toSource(), HelloArray.toSource());
+ Assert.equal(is.available(), 0);
+
+ // Test writing in one big chunk.
+ os.writeBoolean(true);
+ os.write8(4);
+ os.write16(4);
+ os.write16(1024);
+ os.write32(7);
+ os.write32(LargeNum);
+ os.write64(LargeNum);
+ os.write64(1024);
+ os.write64(HugeNum);
+ os.writeFloat(2.5);
+ // os.writeDouble(Math.SQRT2);
+ os.writeStringZ("Mozilla");
+ os.writeWStringZ("Gecko");
+ os.writeBytes(HelloStr, HelloStr.length);
+ os.writeByteArray(HelloArray);
+ // Available should not be zero after a long write like this.
+ Assert.notEqual(is.available(), 0);
+
+ // Test reading in one big chunk.
+ Assert.equal(is.readBoolean(), true);
+ Assert.equal(is.read8(), 4);
+ Assert.equal(is.read16(), 4);
+ Assert.equal(is.read16(), 1024);
+ Assert.equal(is.read32(), 7);
+ Assert.equal(is.read32(), LargeNum);
+ Assert.equal(is.read64(), LargeNum);
+ Assert.equal(is.read64(), 1024);
+ Assert.equal(is.read64(), HugeNum);
+ Assert.equal(is.readFloat(), 2.5);
+ // do_check_eq(is.readDouble(), Math.SQRT2);
+ Assert.equal(is.readCString(), "Mozilla");
+ Assert.equal(is.readString(), "Gecko");
+ // Remember, we wrote HelloStr twice - once as a string, and then as an array.
+ Assert.equal(is.available(), HelloStr.length * 2);
+ msg = is.readBytes(HelloStr.length);
+ Assert.equal(msg, HelloStr);
+ msg = null;
+ countObj.value = -1;
+ Assert.equal(is.available(), HelloStr.length);
+ msg = is.readByteArray(HelloStr.length);
+ Assert.equal(typeof msg, typeof HelloArray);
+ Assert.equal(msg.toSource(), HelloArray.toSource());
+ Assert.equal(is.available(), 0);
+
+ // Test for invalid actions.
+ os.close();
+ is.close();
+
+ try {
+ os.writeBoolean(false);
+ do_throw("Not reached!");
+ } catch (e) {
+ if (
+ !(e instanceof Ci.nsIException && e.result == Cr.NS_BASE_STREAM_CLOSED)
+ ) {
+ throw e;
+ }
+ // do nothing
+ }
+
+ try {
+ is.available();
+ do_throw("Not reached!");
+ } catch (e) {
+ if (
+ !(e instanceof Ci.nsIException && e.result == Cr.NS_BASE_STREAM_CLOSED)
+ ) {
+ throw e;
+ }
+ // do nothing
+ }
+
+ try {
+ is.readBoolean();
+ do_throw("Not reached!");
+ } catch (e) {
+ if (!(e instanceof Ci.nsIException && e.result == Cr.NS_ERROR_FAILURE)) {
+ throw e;
+ }
+ // do nothing
+ }
+}
+
+function run_test() {
+ test_binary_streams();
+}
diff --git a/xpcom/tests/unit/test_stringstream.js b/xpcom/tests/unit/test_stringstream.js
new file mode 100644
index 0000000000..0b9dcf3c5e
--- /dev/null
+++ b/xpcom/tests/unit/test_stringstream.js
@@ -0,0 +1,20 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 4 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+function run_test() {
+ var s = Cc["@mozilla.org/io/string-input-stream;1"].createInstance(
+ Ci.nsIStringInputStream
+ );
+ var body = "This is a test";
+ s.setData(body, body.length);
+ Assert.equal(s.available(), body.length);
+
+ var sis = Cc["@mozilla.org/scriptableinputstream;1"].createInstance(
+ Ci.nsIScriptableInputStream
+ );
+ sis.init(s);
+
+ Assert.equal(sis.read(body.length), body);
+}
diff --git a/xpcom/tests/unit/test_symlinks.js b/xpcom/tests/unit/test_symlinks.js
new file mode 100644
index 0000000000..fb89a1c437
--- /dev/null
+++ b/xpcom/tests/unit/test_symlinks.js
@@ -0,0 +1,142 @@
+const CWD = do_get_cwd();
+
+const DIR_TARGET = "target";
+const DIR_LINK = "link";
+const DIR_LINK_LINK = "link_link";
+const FILE_TARGET = "target.txt";
+const FILE_LINK = "link.txt";
+const FILE_LINK_LINK = "link_link.txt";
+
+const DOES_NOT_EXIST = "doesnotexist";
+const DANGLING_LINK = "dangling_link";
+const LOOP_LINK = "loop_link";
+
+const nsIFile = Ci.nsIFile;
+
+var process;
+function createSymLink(from, to) {
+ if (!process) {
+ var ln = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
+ ln.initWithPath("/bin/ln");
+
+ process = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess);
+ process.init(ln);
+ }
+
+ const args = ["-s", from, to];
+ process.run(true, args, args.length);
+ Assert.equal(process.exitValue, 0);
+}
+
+function makeSymLink(from, toName, relative) {
+ var to = from.parent;
+ to.append(toName);
+
+ if (relative) {
+ createSymLink(from.leafName, to.path);
+ } else {
+ createSymLink(from.path, to.path);
+ }
+
+ Assert.ok(to.isSymlink());
+
+ print("---");
+ print(from.path);
+ print(to.path);
+ print(to.target);
+
+ if (from.leafName != DOES_NOT_EXIST && from.isSymlink()) {
+ // XXXjag wish I could set followLinks to false so we'd just get
+ // the symlink's direct target instead of the final target.
+ Assert.equal(from.target, to.target);
+ } else {
+ Assert.equal(from.path, to.target);
+ }
+
+ return to;
+}
+
+function setupTestDir(testDir, relative) {
+ var targetDir = testDir.clone();
+ targetDir.append(DIR_TARGET);
+
+ if (testDir.exists()) {
+ testDir.remove(true);
+ }
+ Assert.ok(!testDir.exists());
+
+ testDir.create(nsIFile.DIRECTORY_TYPE, 0o777);
+
+ targetDir.create(nsIFile.DIRECTORY_TYPE, 0o777);
+
+ var targetFile = testDir.clone();
+ targetFile.append(FILE_TARGET);
+ targetFile.create(nsIFile.NORMAL_FILE_TYPE, 0o666);
+
+ var imaginary = testDir.clone();
+ imaginary.append(DOES_NOT_EXIST);
+
+ var loop = testDir.clone();
+ loop.append(LOOP_LINK);
+
+ var dirLink = makeSymLink(targetDir, DIR_LINK, relative);
+ var fileLink = makeSymLink(targetFile, FILE_LINK, relative);
+
+ makeSymLink(dirLink, DIR_LINK_LINK, relative);
+ makeSymLink(fileLink, FILE_LINK_LINK, relative);
+
+ makeSymLink(imaginary, DANGLING_LINK, relative);
+
+ try {
+ makeSymLink(loop, LOOP_LINK, relative);
+ Assert.ok(false);
+ } catch (e) {}
+}
+
+function createSpaces(dirs, files, links) {
+ function longest(a, b) {
+ return a.length > b.length ? a : b;
+ }
+ return dirs
+ .concat(files, links)
+ .reduce(longest, "")
+ .replace(/./g, " ");
+}
+
+function testSymLinks(testDir, relative) {
+ setupTestDir(testDir, relative);
+
+ const dirLinks = [DIR_LINK, DIR_LINK_LINK];
+ const fileLinks = [FILE_LINK, FILE_LINK_LINK];
+ const otherLinks = [DANGLING_LINK, LOOP_LINK];
+ const dirs = [DIR_TARGET].concat(dirLinks);
+ const files = [FILE_TARGET].concat(fileLinks);
+ const links = otherLinks.concat(dirLinks, fileLinks);
+
+ const spaces = createSpaces(dirs, files, links);
+ const bools = { false: " false", true: " true " };
+ print(spaces + " dir file symlink");
+ var dirEntries = testDir.directoryEntries;
+ while (dirEntries.hasMoreElements()) {
+ const file = dirEntries.nextFile;
+ const name = file.leafName;
+ print(
+ name +
+ spaces.substring(name.length) +
+ bools[file.isDirectory()] +
+ bools[file.isFile()] +
+ bools[file.isSymlink()]
+ );
+ Assert.equal(file.isDirectory(), dirs.includes(name));
+ Assert.equal(file.isFile(), files.includes(name));
+ Assert.equal(file.isSymlink(), links.includes(name));
+ }
+}
+
+function run_test() {
+ var testDir = CWD;
+ testDir.append("test_symlinks");
+
+ testSymLinks(testDir, false);
+ testSymLinks(testDir, true);
+}
diff --git a/xpcom/tests/unit/test_systemInfo.js b/xpcom/tests/unit/test_systemInfo.js
new file mode 100644
index 0000000000..5f4ad2dc58
--- /dev/null
+++ b/xpcom/tests/unit/test_systemInfo.js
@@ -0,0 +1,26 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+function run_test() {
+ const PROPERTIES = [
+ "name",
+ "arch",
+ "version",
+ "pagesize",
+ "pageshift",
+ "memmapalign",
+ "memsize",
+ ];
+ let sysInfo = Services.sysinfo;
+
+ PROPERTIES.forEach(function(aPropertyName) {
+ print("Testing property: " + aPropertyName);
+ let value = sysInfo.getProperty(aPropertyName);
+ Assert.ok(!!value);
+ });
+
+ // This property must exist, but its value might be zero.
+ print("Testing property: umask");
+ Assert.equal(typeof sysInfo.getProperty("umask"), "number");
+}
diff --git a/xpcom/tests/unit/test_versioncomparator.js b/xpcom/tests/unit/test_versioncomparator.js
new file mode 100644
index 0000000000..5744d62721
--- /dev/null
+++ b/xpcom/tests/unit/test_versioncomparator.js
@@ -0,0 +1,55 @@
+// Versions to test listed in ascending order, none can be equal
+var comparisons = [
+ "pre",
+ // A number that is too large to be supported should be normalized to 0.
+ String(0x1f0000000),
+ "0.9",
+ "0.9.1",
+ "1.0pre1",
+ "1.0pre2",
+ "1.0",
+ "1.1pre",
+ "1.1pre1a",
+ "1.1pre1",
+ "1.1pre10a",
+ "1.1pre10",
+ "1.1",
+ "1.1.0.1",
+ "1.1.1",
+ "1.1.*",
+ "1.*",
+ "2.0",
+ "2.1",
+ "3.0.-1",
+ "3.0",
+];
+
+// Every version in this list means the same version number
+var equality = ["1.1pre", "1.1pre0", "1.0+"];
+
+function run_test() {
+ for (var i = 0; i < comparisons.length; i++) {
+ for (var j = 0; j < comparisons.length; j++) {
+ var result = Services.vc.compare(comparisons[i], comparisons[j]);
+ if (i == j) {
+ if (result != 0) {
+ do_throw(comparisons[i] + " should be the same as itself");
+ }
+ } else if (i < j) {
+ if (!(result < 0)) {
+ do_throw(comparisons[i] + " should be less than " + comparisons[j]);
+ }
+ } else if (!(result > 0)) {
+ do_throw(comparisons[i] + " should be greater than " + comparisons[j]);
+ }
+ }
+ }
+
+ for (i = 0; i < equality.length; i++) {
+ for (j = 0; j < equality.length; j++) {
+ if (Services.vc.compare(equality[i], equality[j]) != 0) {
+ do_throw(equality[i] + " should equal " + equality[j]);
+ }
+ }
+ }
+}
diff --git a/xpcom/tests/unit/test_windows_cmdline_file.js b/xpcom/tests/unit/test_windows_cmdline_file.js
new file mode 100644
index 0000000000..318f93ebec
--- /dev/null
+++ b/xpcom/tests/unit/test_windows_cmdline_file.js
@@ -0,0 +1,22 @@
+let executableFile = Services.dirsvc.get("CurProcD", Ci.nsIFile);
+executableFile.append("xpcshell.exe");
+function run_test() {
+ let quote = '"'; // Windows' cmd processor doesn't actually use single quotes.
+ for (let suffix of ["", " -osint", ` --blah "%PROGRAMFILES%"`]) {
+ let cmdline = quote + executableFile.path + quote + suffix;
+ info(`Testing with ${cmdline}`);
+ let f = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFileWin);
+ f.initWithCommandLine(cmdline);
+ Assert.equal(
+ f.path,
+ executableFile.path,
+ "Should be able to recover executable path"
+ );
+ }
+
+ let f = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFileWin);
+ f.initWithCommandLine("%ComSpec% -c echo 'hi'");
+ let cmd = Services.dirsvc.get("SysD", Ci.nsIFile);
+ cmd.append("cmd.exe");
+ Assert.equal(f.path, cmd.path, "Should be able to replace env vars.");
+}
diff --git a/xpcom/tests/unit/test_windows_registry.js b/xpcom/tests/unit/test_windows_registry.js
new file mode 100644
index 0000000000..6b89f55502
--- /dev/null
+++ b/xpcom/tests/unit/test_windows_registry.js
@@ -0,0 +1,237 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et: */
+
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+const nsIWindowsRegKey = Ci.nsIWindowsRegKey;
+let regKeyComponent = Cc["@mozilla.org/windows-registry-key;1"];
+
+function run_test() {
+ //* create a key structure in a spot that's normally writable (somewhere under HKCU).
+ let testKey = regKeyComponent.createInstance(nsIWindowsRegKey);
+
+ // If it's already present because a previous test crashed or didn't clean up properly, clean it up first.
+ let keyName = BASE_PATH + "\\" + TESTDATA_KEYNAME;
+ setup_test_run(testKey, keyName);
+
+ //* test that the write* functions write stuff
+ test_writing_functions(testKey);
+
+ //* check that the valueCount/getValueName functions work for the values we just wrote
+ test_value_functions(testKey);
+
+ //* check that the get* functions work for the values we just wrote.
+ test_reading_functions(testKey);
+
+ //* check that the get* functions fail with the right exception codes if we ask for the wrong type or if the value name doesn't exist at all
+ test_invalidread_functions(testKey);
+
+ //* check that creating/enumerating/deleting child keys works
+ test_childkey_functions(testKey);
+
+ test_watching_functions(testKey);
+
+ //* clean up
+ cleanup_test_run(testKey, keyName);
+}
+
+function setup_test_run(testKey, keyName) {
+ info("Setup test run");
+ try {
+ testKey.open(
+ nsIWindowsRegKey.ROOT_KEY_CURRENT_USER,
+ keyName,
+ nsIWindowsRegKey.ACCESS_READ
+ );
+ info("Test key exists. Needs cleanup.");
+ cleanup_test_run(testKey, keyName);
+ } catch (e) {
+ if (!(e instanceof Ci.nsIException && e.result == Cr.NS_ERROR_FAILURE)) {
+ throw e;
+ }
+ }
+
+ testKey.create(
+ nsIWindowsRegKey.ROOT_KEY_CURRENT_USER,
+ keyName,
+ nsIWindowsRegKey.ACCESS_ALL
+ );
+}
+
+function test_writing_functions(testKey) {
+ strictEqual(testKey.valueCount, 0);
+
+ strictEqual(testKey.hasValue(TESTDATA_STRNAME), false);
+ testKey.writeStringValue(TESTDATA_STRNAME, TESTDATA_STRVALUE);
+ strictEqual(testKey.hasValue(TESTDATA_STRNAME), true);
+
+ strictEqual(testKey.hasValue(TESTDATA_INTNAME), false);
+ testKey.writeIntValue(TESTDATA_INTNAME, TESTDATA_INTVALUE);
+
+ strictEqual(testKey.hasValue(TESTDATA_INT64NAME), false);
+ testKey.writeInt64Value(TESTDATA_INT64NAME, TESTDATA_INT64VALUE);
+
+ strictEqual(testKey.hasValue(TESTDATA_BINARYNAME), false);
+ testKey.writeBinaryValue(TESTDATA_BINARYNAME, TESTDATA_BINARYVALUE);
+}
+
+function test_value_functions(testKey) {
+ strictEqual(testKey.valueCount, 4);
+ strictEqual(testKey.getValueName(0), TESTDATA_STRNAME);
+ strictEqual(testKey.getValueName(1), TESTDATA_INTNAME);
+ strictEqual(testKey.getValueName(2), TESTDATA_INT64NAME);
+ strictEqual(testKey.getValueName(3), TESTDATA_BINARYNAME);
+}
+
+function test_reading_functions(testKey) {
+ strictEqual(
+ testKey.getValueType(TESTDATA_STRNAME),
+ nsIWindowsRegKey.TYPE_STRING
+ );
+ strictEqual(testKey.readStringValue(TESTDATA_STRNAME), TESTDATA_STRVALUE);
+
+ strictEqual(
+ testKey.getValueType(TESTDATA_INTNAME),
+ nsIWindowsRegKey.TYPE_INT
+ );
+ strictEqual(testKey.readIntValue(TESTDATA_INTNAME), TESTDATA_INTVALUE);
+
+ strictEqual(
+ testKey.getValueType(TESTDATA_INT64NAME),
+ nsIWindowsRegKey.TYPE_INT64
+ );
+ strictEqual(testKey.readInt64Value(TESTDATA_INT64NAME), TESTDATA_INT64VALUE);
+
+ strictEqual(
+ testKey.getValueType(TESTDATA_BINARYNAME),
+ nsIWindowsRegKey.TYPE_BINARY
+ );
+ strictEqual(
+ testKey.readBinaryValue(TESTDATA_BINARYNAME),
+ TESTDATA_BINARYVALUE
+ );
+}
+
+function test_invalidread_functions(testKey) {
+ try {
+ testKey.readIntValue(TESTDATA_STRNAME);
+ do_throw("Reading an integer from a string registry value should throw.");
+ } catch (e) {
+ if (!(e instanceof Ci.nsIException && e.result == Cr.NS_ERROR_FAILURE)) {
+ throw e;
+ }
+ }
+
+ try {
+ let val = testKey.readStringValue(TESTDATA_INTNAME);
+ do_throw(
+ "Reading an string from an Int registry value should throw." + val
+ );
+ } catch (e) {
+ if (!(e instanceof Ci.nsIException && e.result == Cr.NS_ERROR_FAILURE)) {
+ throw e;
+ }
+ }
+
+ try {
+ testKey.readStringValue(TESTDATA_INT64NAME);
+ do_throw("Reading an string from an Int64 registry value should throw.");
+ } catch (e) {
+ if (!(e instanceof Ci.nsIException && e.result == Cr.NS_ERROR_FAILURE)) {
+ throw e;
+ }
+ }
+
+ try {
+ testKey.readStringValue(TESTDATA_BINARYNAME);
+ do_throw("Reading a string from an Binary registry value should throw.");
+ } catch (e) {
+ if (!(e instanceof Ci.nsIException && e.result == Cr.NS_ERROR_FAILURE)) {
+ throw e;
+ }
+ }
+}
+
+function test_childkey_functions(testKey) {
+ strictEqual(testKey.childCount, 0);
+ strictEqual(testKey.hasChild(TESTDATA_CHILD_KEY), false);
+
+ let childKey = testKey.createChild(
+ TESTDATA_CHILD_KEY,
+ nsIWindowsRegKey.ACCESS_ALL
+ );
+ childKey.close();
+
+ strictEqual(testKey.childCount, 1);
+ strictEqual(testKey.hasChild(TESTDATA_CHILD_KEY), true);
+ strictEqual(testKey.getChildName(0), TESTDATA_CHILD_KEY);
+
+ childKey = testKey.openChild(TESTDATA_CHILD_KEY, nsIWindowsRegKey.ACCESS_ALL);
+ testKey.removeChild(TESTDATA_CHILD_KEY);
+ strictEqual(testKey.childCount, 0);
+ strictEqual(testKey.hasChild(TESTDATA_CHILD_KEY), false);
+}
+
+function test_watching_functions(testKey) {
+ strictEqual(testKey.isWatching(), false);
+ strictEqual(testKey.hasChanged(), false);
+
+ testKey.startWatching(true);
+ strictEqual(testKey.isWatching(), true);
+
+ testKey.stopWatching();
+ strictEqual(testKey.isWatching(), false);
+
+ // Create a child key, and update a value
+ let childKey = testKey.createChild(
+ TESTDATA_CHILD_KEY,
+ nsIWindowsRegKey.ACCESS_ALL
+ );
+ childKey.writeIntValue(TESTDATA_INTNAME, TESTDATA_INTVALUE);
+
+ // Start a recursive watch, and update the child's value
+ testKey.startWatching(true);
+ strictEqual(testKey.isWatching(), true);
+
+ childKey.writeIntValue(TESTDATA_INTNAME, 0);
+ strictEqual(testKey.hasChanged(), true);
+ testKey.stopWatching();
+ strictEqual(testKey.isWatching(), false);
+
+ childKey.removeValue(TESTDATA_INTNAME);
+ childKey.close();
+ testKey.removeChild(TESTDATA_CHILD_KEY);
+}
+
+function cleanup_test_run(testKey, keyName) {
+ info("Cleaning up test.");
+
+ for (var i = 0; i < testKey.childCount; i++) {
+ testKey.removeChild(testKey.getChildName(i));
+ }
+ testKey.close();
+
+ let baseKey = regKeyComponent.createInstance(nsIWindowsRegKey);
+ baseKey.open(
+ nsIWindowsRegKey.ROOT_KEY_CURRENT_USER,
+ BASE_PATH,
+ nsIWindowsRegKey.ACCESS_ALL
+ );
+ baseKey.removeChild(TESTDATA_KEYNAME);
+ baseKey.close();
+}
+
+// Test data used above.
+const BASE_PATH = "SOFTWARE";
+const TESTDATA_KEYNAME = "TestRegXPC";
+const TESTDATA_STRNAME = "AString";
+const TESTDATA_STRVALUE = "The quick brown fox jumps over the lazy dog.";
+const TESTDATA_INTNAME = "AnInteger";
+const TESTDATA_INTVALUE = 65536;
+const TESTDATA_INT64NAME = "AnInt64";
+const TESTDATA_INT64VALUE = 9223372036854775000;
+const TESTDATA_BINARYNAME = "ABinary";
+const TESTDATA_BINARYVALUE = "She sells seashells by the seashore";
+const TESTDATA_CHILD_KEY = "TestChildKey";
diff --git a/xpcom/tests/unit/xpcshell.ini b/xpcom/tests/unit/xpcshell.ini
new file mode 100644
index 0000000000..ed370070fc
--- /dev/null
+++ b/xpcom/tests/unit/xpcshell.ini
@@ -0,0 +1,66 @@
+[DEFAULT]
+head = head_xpcom.js
+support-files =
+ data/**
+ xpcomtest.xpt
+generated-files =
+ xpcomtest.xpt
+
+[test_bug121341.js]
+[test_bug325418.js]
+[test_bug332389.js]
+[test_bug333505.js]
+[test_bug364285-1.js]
+[test_bug374754.js]
+[test_bug476919.js]
+# Creating a symlink requires admin or developer mode on Windows.
+skip-if = os == "win"
+# Bug 676998: test fails consistently on Android
+fail-if = os == "android"
+[test_bug478086.js]
+[test_bug1434856.js]
+[test_debugger_malloc_size_of.js]
+[test_file_createUnique.js]
+[test_file_equality.js]
+[test_hidden_files.js]
+[test_home.js]
+# Bug 676998: test fails consistently on Android
+fail-if = os == "android"
+[test_iniParser.js]
+[test_ioutil.js]
+[test_localfile.js]
+[test_mac_bundle.js]
+[test_mac_xattrs.js]
+skip-if = os != "mac"
+[test_nsIMutableArray.js]
+[test_nsIProcess.js]
+skip-if = os == "win" || os == "linux" || os == "android" # bug 582821, bug 1325609, Bug 676998, Bug 1631671
+[test_nsIProcess_stress.js]
+skip-if = os == "win" || ccov # bug 676412, test isn't needed on windows and runs really slowly, bug 1394989
+[test_pipe.js]
+[test_process_directives.js]
+[test_process_directives_child.js]
+skip-if = os == "android"
+[test_storagestream.js]
+[test_streams.js]
+[test_seek_multiplex.js]
+[test_stringstream.js]
+[test_symlinks.js]
+# Creating a symlink requires admin or developer mode on Windows.
+skip-if = os == "win"
+# Bug 676998: test fails consistently on Android
+fail-if = os == "android"
+[test_systemInfo.js]
+[test_versioncomparator.js]
+skip-if =
+ os == "win" && asan # Bug 1763002
+[test_windows_cmdline_file.js]
+skip-if = os != "win"
+[test_bug745466.js]
+skip-if = os == "win"
+# Bug 676998: test fails consistently on Android
+fail-if = os == "android"
+[test_file_renameTo.js]
+[test_notxpcom_scriptable.js]
+[test_windows_registry.js]
+skip-if = os != "win"