You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by fi...@apache.org on 2013/05/24 01:41:32 UTC

[11/38] updated android, ios, bb libraries to 2.8.x branch. fixed a few assertions with project changes. removed blackberry support until create script can be finalized.

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/88ad654c/lib/cordova-blackberry/framework/test/unit/lib/policy/whitelist.js
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/framework/test/unit/lib/policy/whitelist.js b/lib/cordova-blackberry/framework/test/unit/lib/policy/whitelist.js
new file mode 100644
index 0000000..59f9425
--- /dev/null
+++ b/lib/cordova-blackberry/framework/test/unit/lib/policy/whitelist.js
@@ -0,0 +1,859 @@
+/*
+ * Copyright 2011 Research In Motion Limited.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var srcPath = __dirname + "/../../../../lib/",
+    Whitelist = require(srcPath + "policy/whitelist").Whitelist;
+
+describe("whitelist", function () {
+    describe("when user includes a wildcard access", function () {
+        it("can allow access to any domain not from XHR using uri *", function () {
+            var whitelist = new Whitelist({
+                hasMultiAccess : true,
+                accessList : null
+            });
+
+            expect(whitelist.isAccessAllowed("http://www.google.com")).toEqual(true);
+            expect(whitelist.isAccessAllowed("http://www.msn.com")).toEqual(true);
+            expect(whitelist.isAccessAllowed("http://www.cnn.com")).toEqual(true);
+            expect(whitelist.isAccessAllowed("http://www.rim.com")).toEqual(true);
+            expect(whitelist.isAccessAllowed("local:///index.html")).toEqual(true);
+            expect(whitelist.isAccessAllowed("file://store/home/user/documents/file.doc")).toEqual(true);
+        });
+        it("can allow access to explicit domains only when XHR using uri *", function () {
+            var whitelist = new Whitelist({
+                hasMultiAccess : true,
+                accessList : [
+                    {
+                        uri : "http://google.com",
+                        allowSubDomain : true,
+                        features : null
+                    }
+                ]
+            });
+
+            expect(whitelist.isAccessAllowed("http://www.google.com", true)).toEqual(true);
+            expect(whitelist.isAccessAllowed("http://www.google.com/a/b/c", true)).toEqual(true);
+            expect(whitelist.isAccessAllowed("http://www.msn.com", true)).toEqual(false);
+            expect(whitelist.isAccessAllowed("http://www.cnn.com", true)).toEqual(false);
+        });
+    });
+
+    describe("when user does not include a wildcard access", function () {
+        it("can deny all web access when no uris are whitelisted", function () {
+            var whitelist = new Whitelist({
+                hasMultiAccess : false,
+                accessList : null
+            });
+
+            expect(whitelist.isAccessAllowed("http://www.google.com")).toEqual(false);
+        });
+
+        it("can deny all API access when no uris are whitelisted", function () {
+            var whitelist = new Whitelist({
+                hasMultiAccess : false,
+                accessList : null
+            });
+
+            expect(whitelist.isFeatureAllowed("http://www.google.com"), "blackberry.app").toEqual(false);
+        });
+
+        it("can return empty feature list when nothing is whitelisted", function () {
+            var whitelist = new Whitelist({
+                hasMultiAccess : false,
+                accessList : null
+            });
+
+            expect(whitelist.getFeaturesForUrl("http://www.google.com")).toEqual([]);
+        });
+
+        it("can allow access to whitelisted HTTP URL", function () {
+            var whitelist = new Whitelist({
+                hasMultiAccess : false,
+                accessList : [{
+                    uri : "http://google.com",
+                    allowSubDomain : true,
+                    features : null
+                }]
+            });
+
+            expect(whitelist.isAccessAllowed("http://www.google.com")).toEqual(true);
+            expect(whitelist.isAccessAllowed("http://www.cnn.com")).toEqual(false);
+        });
+
+        it("can allow access to whitelisted URL with different case (host)", function () {
+            var whitelist = new Whitelist({
+                hasMultiAccess : false,
+                accessList : [{
+                    uri : "http://google.com",
+                    allowSubDomain : true,
+                    features : null
+                },
+                {
+                    uri : "http://ABC.com",
+                    allowSubDomain : true,
+                    features : null
+                }]
+            });
+
+            expect(whitelist.isAccessAllowed("http://www.GOOGLE.com")).toEqual(true);
+            expect(whitelist.isAccessAllowed("http://www.abc.com")).toEqual(true);
+        });
+
+        it("can allow access to whitelisted URL with different case (path)", function () {
+            var whitelist = new Whitelist({
+                hasMultiAccess : false,
+                accessList : [{
+                    uri : "http://google.com/SOME/path",
+                    allowSubDomain : true,
+                    features : null
+                },
+                {
+                    uri : "http://google.com/another/path",
+                    allowSubDomain : true,
+                    features : null
+                }]
+            });
+
+            expect(whitelist.isAccessAllowed("http://www.google.com/some/path")).toEqual(true);
+            expect(whitelist.isAccessAllowed("http://www.google.com/ANOTHER/path")).toEqual(true);
+        });
+
+        it("can deny access to non-whitelisted HTTP URL", function () {
+            var whitelist = new Whitelist({
+                hasMultiAccess : false,
+                accessList : [{
+                    uri : "http://google.com",
+                    allowSubDomain : true,
+                    features : null
+                }]
+            });
+
+            expect(whitelist.isAccessAllowed("http://www.cnn.com")).toEqual(false);
+        });
+
+        it("can allow access to whitelisted feature for whitelisted HTTP uris", function () {
+            var whitelist = new Whitelist({
+                hasMultiAccess : false,
+                accessList : [
+                    {
+                        uri : "http://google.com",
+                        allowSubDomain : false,
+                        features : [{
+                            id : "blackberry.app",
+                            required : true,
+                            version : "1.0.0"
+                        }]
+                    }, {
+                        uri: "http://smoketest1-vmyyz.labyyz.testnet.rim.net:8080/",
+                        allowSubDomain: false,
+                        features: [{
+                            id : "blackberry.app",
+                            required : true,
+                            version : "1.0.0"
+                        }]
+                    }
+                ]
+            });
+
+            expect(whitelist.isFeatureAllowed("http://google.com", "blackberry.app")).toEqual(true);
+            expect(whitelist.isFeatureAllowed("http://smoketest1-vmyyz.labyyz.testnet.rim.net:8080/a/webworks.html", "blackberry.app")).toEqual(true);
+        });
+
+        it("can deny access to non-whitelisted feature for whitelisted HTTP uris", function () {
+            var whitelist = new Whitelist({
+                hasMultiAccess : false,
+                accessList : [{
+                    uri : "http://google.com",
+                    allowSubDomain : false,
+                    features : [{
+                        id : "blackberry.app",
+                        required : true,
+                        version : "1.0.0"
+                    }]
+                }]
+            });
+
+            expect(whitelist.isFeatureAllowed("http://google.com", "blackberry.io.file")).toEqual(false);
+        });
+
+        it("can get all whitelisted features for url", function () {
+            var whitelist = new Whitelist({
+                    hasMultiAccess : false,
+                    accessList : [{
+                        uri : "http://google.com",
+                        allowSubDomain : false,
+                        features : [{
+                            id : "blackberry.app",
+                            required : true,
+                            version : "1.0.0"
+                        }, {
+                            id : "blackberry.media.camera",
+                            required : true,
+                            version : "1.0.0"
+                        }, {
+                            id : "blackberry.io.dir",
+                            required : true,
+                            version : "1.0.0"
+                        }]
+                    }]
+                });
+
+            expect(whitelist.getFeaturesForUrl("http://google.com")).toContain("blackberry.app");
+            expect(whitelist.getFeaturesForUrl("http://google.com")).toContain("blackberry.media.camera");
+            expect(whitelist.getFeaturesForUrl("http://google.com")).toContain("blackberry.io.dir");
+            expect(whitelist.getFeaturesForUrl("http://www.wikipedia.org")).toEqual([]);
+        });
+
+        it("can allow access for query strings using a query string wildcard", function () {
+            var whitelist = new Whitelist({
+                hasMultiAccess : false,
+                accessList : [{
+                    uri : "http://www.google.com/search?*",
+                    allowSubDomain : true,
+                    features : null
+                }]
+            });
+
+            expect(whitelist.isAccessAllowed("http://www.google.com/search?q=awesome")).toEqual(true);
+            expect(whitelist.isAccessAllowed("http://www.google.com/search?a=anyLetter")).toEqual(true);
+            expect(whitelist.isAccessAllowed("http://www.google.com/search")).toEqual(false);
+            expect(whitelist.isAccessAllowed("http://www.google.com/blah?q=awesome")).toEqual(false);
+        });
+
+        it("can deny access for query strings without a query string wildcard", function () {
+            var whitelist = new Whitelist({
+                hasMultiAccess : false,
+                accessList : [{
+                    uri : "http://www.google.com/search",
+                    allowSubDomain : true,
+                    features : null
+                }]
+            });
+
+            expect(whitelist.isAccessAllowed("http://www.google.com/search?q=awesome", true)).toEqual(false);
+            expect(whitelist.isAccessAllowed("http://www.google.com/search?a=anyLetter", true)).toEqual(false);
+        });
+
+        it("can allow access for ports given just the whitelist url", function () {
+            var whitelist = new Whitelist({
+                hasMultiAccess : false,
+                accessList : [{
+                    uri : "http://www.awesome.com",
+                    allowSubDomain : true,
+                    features : null
+                }]
+            });
+
+            expect(whitelist.isAccessAllowed("http://www.awesome.com:9000")).toEqual(true);
+        });
+
+        it("allows api access for ports given just the whitelist url", function () {
+            var whitelist = new Whitelist({
+                hasMultiAccess : false,
+                accessList : [{
+                    uri : "http://www.awesome.com",
+                    allowSubDomain : true,
+                    features : [{
+                        id : "blackberry.app",
+                        required : true,
+                        version : "1.0.0"
+                    }]
+                }]
+            });
+
+            expect(whitelist.isFeatureAllowed("http://www.awesome.com:8080", "blackberry.app")).toEqual(true);
+        });
+
+        it("allows api access for child pages with ports given just the whitelist url", function () {
+            var whitelist = new Whitelist({
+                hasMultiAccess : false,
+                accessList : [{
+                    uri : "http://smoketest8-vmyyz.labyyz.testnet.rim.net/",
+                    allowSubDomain : true,
+                    features : [{
+                        id : "blackberry.app",
+                        required : true,
+                        version : "1.0.0"
+                    }]
+                }]
+            });
+
+            expect(whitelist.isFeatureAllowed("http://www.smoketest8-vmyyz.labyyz.testnet.rim.net:8080//webworks.html", "blackberry.app")).toEqual(true);
+        });
+
+        it("can allow folder level access of whitelisted uris", function () {
+            var whitelist = new Whitelist({
+                hasMultiAccess : false,
+                accessList : [{
+                    uri : "http://www.awesome.com/parent/child",
+                    allowSubDomain : false,
+                    features : null
+                }]
+            });
+
+            expect(whitelist.isAccessAllowed("http://www.awesome.com/parent/child")).toEqual(true);
+        });
+
+        it("can deny access to parent folders of whitelisted uris", function () {
+            var whitelist = new Whitelist({
+                hasMultiAccess : false,
+                accessList : [{
+                    uri : "http://www.awesome.com/parent/child",
+                    allowSubDomain : false,
+                    features : null
+                }]
+            });
+
+            expect(whitelist.isAccessAllowed("http://www.awesome.com/parent")).toEqual(false);
+        });
+
+        it("can deny access to sibling folders of whitelisted uris", function () {
+            var whitelist = new Whitelist({
+                hasMultiAccess : false,
+                accessList : [{
+                    uri : "http://www.awesome.com/parent/child/",
+                    allowSubDomain : false,
+                    features : null
+                }]
+            });
+
+            expect(whitelist.isAccessAllowed("http://www.awesome.com/parent/sibling/")).toEqual(false);
+        });
+
+        it("can deny access to sibling folders of whitelisted uris", function () {
+            var whitelist = new Whitelist({
+                hasMultiAccess : false,
+                accessList : [{
+                    uri : "http://rim4.awesome.com/goodChild/index.html",
+                    allowSubDomain : false,
+                    features : null
+                }]
+            });
+
+            expect(whitelist.isAccessAllowed("http://rim4.awesome.com/goodChild/index.html")).toEqual(true);
+            expect(whitelist.isAccessAllowed("http://rim4.awesome.com/badChild/index.html")).toEqual(false);
+        });
+
+        it("can get whitelisted features at a folder level", function () {
+            var list1 = [{
+                    id : "blackberry.app",
+                    required : true,
+                    version : "1.0.0"
+                }],
+                list2 = [{
+                    id : "blackberry.media.camera",
+                    required : true,
+                    version : "1.0.0"
+                }],
+                whitelist = new Whitelist({
+                    hasMultiAccess : false,
+                    accessList : [{
+                        uri : "http://google.com/ninjas",
+                        allowSubDomain : true,
+                        features : list1
+                    }, {
+                        uri : "http://google.com/pirates",
+                        allowSubDomain : true,
+                        features : list2
+                    }]
+                });
+
+            expect(whitelist.getFeaturesForUrl("http://google.com/ninjas")).toEqual(["blackberry.app"]);
+            expect(whitelist.getFeaturesForUrl("http://google.com/pirates")).toEqual(["blackberry.media.camera"]);
+        });
+
+        it("can allow API permissions at a folder level", function () {
+            var whitelist = new Whitelist({
+                hasMultiAccess : false,
+                accessList : [{
+                    uri : "http://google.com/ninjas",
+                    allowSubDomain : true,
+                    features : [{
+                        id : "blackberry.app",
+                        required : true,
+                        version : "1.0.0"
+                    }]
+                }, {
+                    uri : "http://google.com/pirates",
+                    allowSubDomain : true,
+                    features : [{
+                        id : "blackberry.media.camera",
+                        required : true,
+                        version : "1.0.0"
+                    }]
+                }]
+            });
+
+            expect(whitelist.isFeatureAllowed("http://google.com/ninjas", "blackberry.app")).toEqual(true);
+            expect(whitelist.isFeatureAllowed("http://google.com/pirates", "blackberry.media.camera")).toEqual(true);
+        });
+
+        it("can deny API permissions at a folder level", function () {
+            var whitelist = new Whitelist({
+                hasMultiAccess : false,
+                accessList : [{
+                    uri : "http://google.com/ninjas",
+                    allowSubDomain : true,
+                    features : [{
+                        id : "blackberry.app",
+                        required : true,
+                        version : "1.0.0"
+                    }]
+                }, {
+                    uri : "http://google.com/pirates",
+                    allowSubDomain : true,
+                    features : [{
+                        id : "blackberry.media.camera",
+                        required : true,
+                        version : "1.0.0"
+                    }]
+                }]
+            });
+
+            expect(whitelist.isFeatureAllowed("http://google.com/ninjas", "blackberry.media.camera")).toEqual(false);
+            expect(whitelist.isFeatureAllowed("http://google.com/pirates", "blackberry.app")).toEqual(false);
+        });
+
+        it("can allow access specific folder rules to override more general domain rules", function () {
+            var whitelist = new Whitelist({
+                hasMultiAccess : false,
+                accessList : [{
+                    uri : "http://google.com",
+                    allowSubDomain : true,
+                    features : [{
+                        id : "blackberry.app",
+                        required : true,
+                        version : "1.0.0"
+                    }]
+                }, {
+                    uri : "http://google.com/folder",
+                    allowSubDomain : true,
+                    features : [{
+                        id : "blackberry.media.camera",
+                        required : true,
+                        version : "1.0.0"
+                    }]
+                }]
+            });
+
+            expect(whitelist.isFeatureAllowed("http://google.com/folder", "blackberry.app")).toEqual(false);
+            expect(whitelist.isFeatureAllowed("http://google.com/folder", "blackberry.media.camera")).toEqual(true);
+        });
+
+        describe("when access uris have subdomains", function () {
+            it("can get whitelisted features for subdomains", function () {
+                var whitelist = new Whitelist({
+                    hasMultiAccess : false,
+                    accessList : [{
+                        uri : "http://google.com",
+                        allowSubDomain : true,
+                        features : [{
+                            id : "blackberry.system",
+                            required : true,
+                            version : "1.0.0.0"
+                        }, {
+                            id : "blackberry.media.microphone",
+                            required : true,
+                            version : "1.0.0.0"
+                        }]
+                    }]
+                });
+
+                expect(whitelist.getFeaturesForUrl("http://code.google.com")).toContain("blackberry.media.microphone");
+                expect(whitelist.getFeaturesForUrl("http://code.google.com")).toContain("blackberry.system");
+                expect(whitelist.getFeaturesForUrl("http://translate.google.com/lang=en")).toContain("blackberry.media.microphone");
+                expect(whitelist.getFeaturesForUrl("http://translate.google.com/lang=en")).toContain("blackberry.system");
+                expect(whitelist.getFeaturesForUrl("http://blah.goooooogle.com")).toEqual([]);
+            });
+
+            it("can allow access to whitelisted features for the subdomains", function () {
+                var whitelist = new Whitelist({
+                    hasMultiAccess : false,
+                    accessList : [{
+                        uri : "http://google.com",
+                        allowSubDomain : true,
+                        features : [{
+                            id : "blackberry.app",
+                            required : true,
+                            version : "1.0.0"
+                        }]
+                    }]
+                });
+
+                expect(whitelist.isFeatureAllowed("http://abc.google.com", "blackberry.app")).toEqual(true);
+                expect(whitelist.isFeatureAllowed("http://xyz.google.com", "blackberry.app")).toEqual(true);
+            });
+
+            it("can allow access to subdomains of whitelisted uris", function () {
+                var whitelist = new Whitelist({
+                    hasMultiAccess : false,
+                    accessList : [
+                        {
+                            uri : "http://awesome.com/",
+                            allowSubDomain : true,
+                            features : null
+                        }, {
+                            uri: "http://smoketest9-vmyyz.labyyz.testnet.rim.net:8080",
+                            allowSubDomain: true,
+                            features: null
+                        }
+                    ]
+                });
+
+                expect(whitelist.isAccessAllowed("http://subdomain.awesome.com")).toEqual(true);
+                expect(whitelist.isAccessAllowed("http://www.smoketest9-vmyyz.labyyz.testnet.rim.net:8080")).toEqual(true);
+            });
+
+            it("can disallow access to subdomains of whitelisted uris", function () {
+                var whitelist = new Whitelist({
+                    hasMultiAccess : false,
+                    accessList : [{
+                        uri : "http://awesome.com/",
+                        allowSubDomain : false,
+                        features : null
+                    }]
+                });
+
+                expect(whitelist.isAccessAllowed("http://subdomain.awesome.com")).toEqual(false);
+            });
+
+            it("can disallow access to subdomains of a specified uri", function () {
+                var whitelist = new Whitelist({
+                    hasMultiAccess : false,
+                    accessList : [{
+                        uri : "http://awesome.com/",
+                        allowSubDomain : true,
+                        features : null
+                    }, {
+                        uri : "http://moreawesome.com/",
+                        allowSubDomain : false,
+                        features : null
+                    }]
+                });
+
+                expect(whitelist.isAccessAllowed("http://subdomain.moreawesome.com")).toEqual(false);
+            });
+
+            it("can allow specific subdomain rules to override more general domain rules when subdomains are allowed", function () {
+                var whitelist = new Whitelist({
+                    hasMultiAccess : false,
+                    accessList : [{
+                        uri : "http://google.com",
+                        allowSubDomain : true,
+                        features : [{
+                            id : "blackberry.app",
+                            required : true,
+                            version : "1.0.0"
+                        }]
+                    }, {
+                        uri : "http://sub.google.com",
+                        allowSubDomain : true,
+                        features : [{
+                            id : "blackberry.media.camera",
+                            required : true,
+                            version : "1.0.0"
+                        }]
+                    }]
+                });
+
+                expect(whitelist.isFeatureAllowed("http://sub.google.com", "blackberry.app")).toEqual(false);
+                expect(whitelist.isFeatureAllowed("http://sub.google.com", "blackberry.media.camera")).toEqual(true);
+            });
+
+            it("can get whitelisted features for a more specific subdomain", function () {
+                var whitelist = new Whitelist({
+                    hasMultiAccess : false,
+                    accessList : [{
+                        uri : "http://google.com",
+                        allowSubDomain : false,
+                        features : [{
+                            id : "blackberry.app",
+                            required : true,
+                            version : "1.0.0"
+                        }]
+                    }, {
+                        uri : "http://sub.google.com",
+                        allowSubDomain : false,
+                        features : [{
+                            id : "blackberry.media.camera",
+                            required : true,
+                            version : "1.0.0"
+                        }]
+                    }]
+                });
+
+                expect(whitelist.getFeaturesForUrl("http://google.com")).toContain("blackberry.app");
+                expect(whitelist.getFeaturesForUrl("http://sub.google.com")).toContain("blackberry.media.camera");
+                expect(whitelist.getFeaturesForUrl("http://sub.google.com")).not.toContain("blckberry.app");
+                expect(whitelist.getFeaturesForUrl("http://code.google.com")).toEqual([]);
+            });
+
+            it("can allow specific subdomain rules to override more general domain rules when subdomains are disallowed", function () {
+                var whitelist = new Whitelist({
+                    hasMultiAccess : false,
+                    accessList : [{
+                        uri : "http://google.com",
+                        allowSubDomain : false,
+                        features : [{
+                            id : "blackberry.app",
+                            required : true,
+                            version : "1.0.0"
+                        }]
+                    }, {
+                        uri : "http://sub.google.com",
+                        allowSubDomain : false,
+                        features : [{
+                            id : "blackberry.media.camera",
+                            required : true,
+                            version : "1.0.0"
+                        }]
+                    }]
+                });
+
+                expect(whitelist.isFeatureAllowed("http://sub.google.com", "blackberry.app")).toEqual(false);
+                expect(whitelist.isFeatureAllowed("http://sub.google.com", "blackberry.media.camera")).toEqual(true);
+            });
+        });
+
+        describe("when uris with other protocols are requested", function () {
+            it("can allow access to whitelisted HTTPS URL", function () {
+                var whitelist = new Whitelist({
+                    hasMultiAccess : false,
+                    accessList : [{
+                        uri : "https://google.com",
+                        allowSubDomain : true,
+                        features : null
+                    }]
+                });
+
+                expect(whitelist.isAccessAllowed("https://www.google.com")).toEqual(true);
+                expect(whitelist.isAccessAllowed("https://www.cnn.com")).toEqual(false);
+            });
+
+            it("can deny access to non-whitelisted HTTPS URL", function () {
+                var whitelist = new Whitelist({
+                    hasMultiAccess : false,
+                    accessList : [{
+                        uri : "https://google.com",
+                        allowSubDomain : true,
+                        features : null
+                    }]
+                });
+
+                expect(whitelist.isAccessAllowed("https://www.cnn.com")).toEqual(false);
+            });
+
+            it("can allow access to local URLs", function () {
+                var whitelist = new Whitelist({
+                    hasMultiAccess : false,
+                    accessList : [{
+                        uri : "WIDGET_LOCAL",    // packager always inserts a local access into access list
+                        allowSubDomain : false
+                    }]
+                });
+
+                expect(whitelist.isAccessAllowed("local:///index.html")).toEqual(true);
+                expect(whitelist.isAccessAllowed("local:///appDir/subDir/index.html")).toEqual(true);
+            });
+
+            it("can allow access to whitelisted features for local URLs", function () {
+                var whitelist = new Whitelist({
+                    hasMultiAccess : false,
+                    accessList : [{
+                        uri : "WIDGET_LOCAL",    // packager always inserts a local access into access list
+                        allowSubDomain : false,
+                        features : [{
+                            id : "blackberry.media.microphone",
+                            required : true,
+                            version : "2.0.0"
+                        }, {
+                            id : "blackberry.media.camera",
+                            required : true,
+                            version : "1.0.0"
+                        }]
+                    }]
+                });
+
+                expect(whitelist.isFeatureAllowed("local:///index.html", "blackberry.media.microphone")).toEqual(true);
+                expect(whitelist.isFeatureAllowed("local:///index.html", "blackberry.media.camera")).toEqual(true);
+            });
+
+            it("can allow access to whitelisted file URL", function () {
+                var whitelist = new Whitelist({
+                    hasMultiAccess : false,
+                    accessList : [{
+                        uri : "file://store/home/user/documents",
+                        allowSubDomain : false,
+                        features : null
+                    }]
+                });
+
+                expect(whitelist.isAccessAllowed("file://store/home/user/documents/file.doc")).toEqual(true);
+            });
+
+            it("can access file if rule specifed was file:///", function () {
+                var whitelist = new Whitelist({
+                    hasMultiAccess : false,
+                    accessList : [
+                        {
+                            uri : "file:///accounts/1000/shared/documents/textData.txt",
+                            allowSubDomain : false,
+                            features: []
+                        }
+                    ]
+                });
+
+                expect(whitelist.isAccessAllowed("file:///accounts/1000/shared/documents/textData.txt")).toEqual(true);
+                expect(whitelist.isAccessAllowed("file:///etc/passwd")).toEqual(false);
+            });
+
+            it("can access file if rule specifed was file:///", function () {
+                var whitelist = new Whitelist({
+                    "hasMultiAccess": false,
+                    "accessList": [
+                        {
+                            "features": [],
+                            "uri": "WIDGET_LOCAL",
+                            "allowSubDomain": true
+                        },
+                        {
+                            "features": [],
+                            "uri": "file:///accounts/1000/shared/documents/textData.txt"
+                        }
+                    ]
+                });
+                expect(whitelist.isAccessAllowed("file:///etc/passwd", false)).toEqual(false);
+            });
+
+            it("can deny file access when access file:/// with no rule", function () {
+                var whitelist = new Whitelist({
+                    hasMultiAccess : false,
+                    accessList : null
+                });
+
+                expect(whitelist.isAccessAllowed("file:///accounts/1000/shared/documents/textData.txt")).toEqual(false);
+            });
+
+            it("can allow access to whitelisted file URL from an external startup page", function () {
+                var whitelist = new Whitelist({
+                    content: "http://www.google.com",
+                    hasMultiAccess : false,
+                    accessList : [{
+                        uri : "file://store/home/user/documents",
+                        allowSubDomain : false,
+                        features : null
+                    }]
+                });
+
+                expect(whitelist.isAccessAllowed("file://store/home/user/documents/file.doc")).toEqual(true);
+            });
+
+            it("can allow access to whitelisted local URL from an external startup page", function () {
+                var whitelist = new Whitelist({
+                    content: "http://www.google.com",
+                    hasMultiAccess : false,
+                    accessList : [{
+                        uri : "local://localpage.html",
+                        allowSubDomain : false,
+                        features : null
+                    }]
+                });
+
+                expect(whitelist.isAccessAllowed("local://localpage.html")).toEqual(true);
+            });
+
+            it("can allow access to whitelisted file URL from an external startup page with wildcard access", function () {
+                var whitelist = new Whitelist({
+                    content: "http://www.google.com",
+                    hasMultiAccess : true
+                });
+
+                expect(whitelist.isAccessAllowed("file://store/home/user/documents/file.doc")).toEqual(true);
+            });
+
+            it("can allow access to whitelisted local URL from an external startup page with wildcard access", function () {
+                var whitelist = new Whitelist({
+                    content: "http://www.google.com",
+                    hasMultiAccess : true
+                });
+
+                expect(whitelist.isAccessAllowed("local://localpage.html")).toEqual(true);
+            });
+
+            it("can deny file URL access when no file urls are whitelisted", function () {
+                var whitelist = new Whitelist({
+                    hasMultiAccess : false,
+                    accessList : null
+                });
+
+                expect(whitelist.isAccessAllowed("file://store/home/user/documents/file.doc")).toEqual(false);
+            });
+
+            it("can allow access to a subfolder of a whitelisted file URL", function () {
+                var whitelist = new Whitelist({
+                    hasMultiAccess : false,
+                    accessList : [{
+                        uri : "file://store/home/user/",
+                        allowSubDomain : false,
+                        features : null
+                    }]
+                });
+
+                expect(whitelist.isAccessAllowed("file://store/home/user/documents/file.doc")).toEqual(true);
+            });
+
+            it("can deny access to a different folder of a whitelisted file URL", function () {
+                var whitelist = new Whitelist({
+                    hasMultiAccess : false,
+                    accessList : [{
+                        uri : "http://store.com/home/user/documents",
+                        allowSubDomain : false,
+                        features : null
+                    }]
+                });
+
+                expect(whitelist.isAccessAllowed("http://store.com/home/user/documents/file.doc")).toEqual(true);
+                expect(whitelist.isAccessAllowed("http://store.com/file2.doc")).toEqual(false);
+            });
+
+            it("can allow access to RTSP protocol urls", function () {
+                var whitelist = new Whitelist({
+                    hasMultiAccess : false,
+                    accessList : [{
+                        uri : "rtsp://media.com",
+                        allowSubDomain : false,
+                        features : null
+                    }]
+                });
+
+                expect(whitelist.isAccessAllowed("rtsp://media.com/video.avi")).toEqual(true);
+            });
+
+            it("always allows access to data-uris", function () {
+                var whitelist = new Whitelist({
+                    hasMultiAccess : false,
+                    accessList : [{
+                        uri : "http://awesome.com",
+                        allowSubDomain : false,
+                        features : null
+                    }]
+                });
+
+                expect(whitelist.isAccessAllowed("data:image/png;base64,zamagawdbase64string")).toEqual(true);
+            });
+        });
+    });
+});

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/88ad654c/lib/cordova-blackberry/framework/test/unit/lib/server.js
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/framework/test/unit/lib/server.js b/lib/cordova-blackberry/framework/test/unit/lib/server.js
new file mode 100644
index 0000000..2b89b0a
--- /dev/null
+++ b/lib/cordova-blackberry/framework/test/unit/lib/server.js
@@ -0,0 +1,293 @@
+/*
+ * Copyright 2010-2011 Research In Motion Limited.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+var ROOT = "../../../";
+
+describe("server", function () {
+
+    var server = require(ROOT + "lib/server"),
+        plugin = require(ROOT + "lib/plugins/default"),
+        applicationAPIServer,
+        utils,
+        DEFAULT_SERVICE = "default",
+        DEFAULT_ACTION = "exec",
+        config = {};
+
+    beforeEach(function () {
+        applicationAPIServer = {
+            getReadOnlyFields: function () {}
+        };
+        delete require.cache[require.resolve(ROOT + "lib/utils")];
+        utils = require("../../../lib/utils");
+        spyOn(utils, "loadModule").andCallFake(function (module) {
+            if (module.indexOf("plugin/") >= 0) {
+                // on device, "plugin/blackberry.app/index.js" would exist
+                return applicationAPIServer;
+            } else {
+                return require("../../../lib/" + module);
+            }
+        });
+    });
+
+    describe("when handling requests", function () {
+        var req, res;
+
+        beforeEach(function () {
+            req = {
+                params: {
+                    service: "",
+                    action: ""
+                },
+                body: "",
+                origin: ""
+            };
+            res = {
+                send: jasmine.createSpy()
+            };
+            GLOBAL.frameworkModules = ['plugin/blackberry.app/index.js', 'lib/plugins/default.js'];
+        });
+
+        afterEach(function () {
+            delete GLOBAL.frameworkModules;
+        });
+
+        it("calls the default plugin if the service doesn't exist", function () {
+            var rebuiltRequest = {
+                    params: {
+                        service: DEFAULT_SERVICE,
+                        action: DEFAULT_ACTION,
+                        ext: "not",
+                        method: "here",
+                        args: null
+                    },
+                    body: "",
+                    origin: ""
+                },
+                webview = {};
+
+            spyOn(plugin, DEFAULT_ACTION);
+            req.params.service = "not";
+            req.params.action = "here";
+
+            server.handle(req, res, webview, config);
+
+            expect(plugin[DEFAULT_ACTION]).toHaveBeenCalledWith(
+                rebuiltRequest, jasmine.any(Function),
+                jasmine.any(Function),
+                rebuiltRequest.params.args,
+                {
+                    request: rebuiltRequest,
+                    response: res,
+                    webview: webview,
+                    config: config
+                }
+            );
+        });
+
+        it("returns 404 if the action doesn't exist", function () {
+            req.params.service = "default";
+            req.params.action = "ThisActionDoesNotExist";
+
+            spyOn(console, "error");
+
+            server.handle(req, res);
+            expect(res.send).toHaveBeenCalledWith(404, jasmine.any(String));
+            expect(console.error).toHaveBeenCalled();
+        });
+
+        it("calls the action method on the plugin", function () {
+            var webview = "BLAHBLAHBLAH";
+
+            spyOn(plugin, "exec");
+
+            req.params.service = "default";
+            req.params.action = "exec";
+
+            expect(function () {
+                return server.handle(req, res, webview, config);
+            }).not.toThrow();
+            expect(plugin.exec).toHaveBeenCalledWith(
+                req,
+                jasmine.any(Function),
+                jasmine.any(Function),
+                req.params.args,
+                {
+                    request: req,
+                    response: res,
+                    webview: webview,
+                    config: config
+                });
+        });
+
+        it("parses url encoded args", function () {
+            var webview = "BLAHBLAHBLAH";
+
+            spyOn(plugin, "exec");
+
+            expect(function () {
+                req.params.service = "default";
+                req.params.action = "exec";
+                req.params.args = "a=1&b=2&c=3";
+
+                return server.handle(req, res, webview);
+            }).not.toThrow();
+            expect(plugin.exec).toHaveBeenCalledWith(
+                jasmine.any(Object),
+                jasmine.any(Function),
+                jasmine.any(Function),
+                {
+                    a: '1',
+                    b: '2',
+                    c: '3'
+                },
+                jasmine.any(Object)
+            );
+        });
+
+        it("parses url encoded args", function () {
+            var webview = "BLAHBLAHBLAH";
+
+            spyOn(plugin, "exec");
+
+            expect(function () {
+                req.params.service = "default";
+                req.params.action = "exec";
+                req.body = JSON.stringify({a: '1', b: '2', c: '3'});
+
+                return server.handle(req, res, webview);
+            }).not.toThrow();
+            expect(plugin.exec).toHaveBeenCalledWith(
+                jasmine.any(Object),
+                jasmine.any(Function),
+                jasmine.any(Function),
+                {
+                    a: '1',
+                    b: '2',
+                    c: '3'
+                },
+                jasmine.any(Object)
+            );
+        });
+
+        it("returns the result and code 42 when success callback called", function () {
+            spyOn(plugin, "exec").andCallFake(function (request, succ, fail, body) {
+                succ(["MyFeatureId"]);
+            });
+
+            req.params.service = "default";
+            req.params.action = "exec";
+
+            server.handle(req, res);
+            expect(res.send).toHaveBeenCalledWith(200, encodeURIComponent(JSON.stringify({
+                code: 42,
+                data: ["MyFeatureId"]
+            })));
+        });
+
+        it("returns the result and code -1 when fail callback called", function () {
+            spyOn(plugin, "exec").andCallFake(function (request, succ, fail, body) {
+                fail(-1, "ErrorMessage");
+            });
+
+            req.params.service = "default";
+            req.params.action = "exec";
+
+            server.handle(req, res);
+            expect(res.send).toHaveBeenCalledWith(200, encodeURIComponent(JSON.stringify({
+                code: -1,
+                data: null,
+                msg: "ErrorMessage"
+            })));
+        });
+    });
+
+    describe("when handling feature requests", function () {
+        var req, res;
+
+        beforeEach(function () {
+            req = {
+                params: {
+                    service: "default",
+                    action: "exec",
+                    ext: "blackberry.app",
+                    method: "getReadOnlyFields",
+                    args: null
+                },
+                headers: {
+                    host: ""
+                },
+                url: "",
+                body: "",
+                origin: ""
+            };
+            res = {
+                send: jasmine.createSpy()
+            };
+            GLOBAL.frameworkModules = ['plugin/blackberry.app/index.js', 'lib/plugins/default.js'];
+        });
+
+        afterEach(function () {
+            delete GLOBAL.frameworkModules;
+        });
+
+        it("calls the action method on the feature", function () {
+            var webview = {};
+            spyOn(applicationAPIServer, "getReadOnlyFields");
+            server.handle(req, res, webview, config);
+            expect(applicationAPIServer.getReadOnlyFields).toHaveBeenCalledWith(
+                jasmine.any(Function),
+                jasmine.any(Function),
+                req.params.args,
+                {
+                    request: req,
+                    response: res,
+                    webview: webview,
+                    config: config
+                }
+            );
+        });
+
+        it("returns the result and code 42 when success callback called", function () {
+            var expectedResult = {"getReadOnlyFields": "Yogi bear"};
+
+            spyOn(applicationAPIServer, "getReadOnlyFields").andCallFake(function (success, fail) {
+                success(expectedResult);
+            });
+
+            server.handle(req, res);
+
+            expect(res.send).toHaveBeenCalledWith(200, encodeURIComponent(JSON.stringify({
+                code: 42,
+                data: expectedResult
+            })));
+        });
+
+        it("returns the result and code -1 when fail callback called", function () {
+            var expectedResult = "omg";
+
+            spyOn(applicationAPIServer, "getReadOnlyFields").andCallFake(function (success, fail) {
+                fail(-1, expectedResult);
+            });
+
+            server.handle(req, res);
+
+            expect(res.send).toHaveBeenCalledWith(200, encodeURIComponent(JSON.stringify({
+                code: -1,
+                data: null,
+                msg: expectedResult
+            })));
+        });
+    });
+});

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/88ad654c/lib/cordova-blackberry/framework/test/unit/lib/utils.js
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/framework/test/unit/lib/utils.js b/lib/cordova-blackberry/framework/test/unit/lib/utils.js
new file mode 100644
index 0000000..4b7f5a8
--- /dev/null
+++ b/lib/cordova-blackberry/framework/test/unit/lib/utils.js
@@ -0,0 +1,280 @@
+/*
+ * Copyright 2010-2011 Research In Motion Limited.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var srcPath = __dirname + '/../../../lib/';
+
+describe("Utils", function () {
+    var utils = require(srcPath + 'utils.js');
+
+    describe("endsWith", function () {
+        it("returns true when a string ends with another", function () {
+            expect(utils.endsWith("www.smoketest9-vmyyz.labyyz.testnet.rim.net:8080", ".smoketest9-vmyyz.labyyz.testnet.rim.net:8080")).toEqual(true);
+        });
+    });
+
+    it("Verify that the filenameToImageMIME is defined", function () {
+        expect(utils.fileNameToImageMIME).toBeDefined();
+    });
+
+    it("Verify that the proper PNG MIME types are returned", function () {
+        expect(utils.fileNameToImageMIME("test.png")).toEqual("image/png");
+    });
+
+    it("Verify that the proper period MIME types are returned", function () {
+        expect(utils.fileNameToImageMIME("test.t.png")).toEqual("image/png");
+    });
+
+    it("Verify that the proper JPG types are returned", function () {
+        expect(utils.fileNameToImageMIME("test.jpg")).toEqual("image/jpeg");
+    });
+
+    it("Verify that the proper GIF types are returned", function () {
+        expect(utils.fileNameToImageMIME("test.gif")).toEqual("image/gif");
+    });
+
+    it("Verify that the proper TIFF types are returned", function () {
+        expect(utils.fileNameToImageMIME("test_test_.tif")).toEqual("image/tiff");
+    });
+
+    it("Verify that the proper TIFF types are returned", function () {
+        expect(utils.fileNameToImageMIME("test_test_.tiff")).toEqual("image/tiff");
+    });
+
+    it("Verify that the proper JPE MIME types are returned", function () {
+        expect(utils.fileNameToImageMIME("test.jpe")).toEqual("image/jpeg");
+    });
+
+    it("Verify that the proper BMP MIME types are returned", function () {
+        expect(utils.fileNameToImageMIME("test.bmp")).toEqual("image/bmp");
+    });
+
+    it("Verify that the proper JPEG MIME types are returned", function () {
+        expect(utils.fileNameToImageMIME("test.jpeg")).toEqual("image/jpeg");
+    });
+
+    it("Verify that the proper SVG MIME types are returned", function () {
+        expect(utils.fileNameToImageMIME("test.svg")).toEqual("image/svg+xml");
+    });
+
+    it("has an invokeInBrowser function", function () {
+        var url = "http://www.webworks.com",
+            mockApplication = {
+                invocation: {
+                    invoke: jasmine.createSpy("invocation.invoke")
+                }
+            },
+            mockWindow = {
+                qnx: {
+                    webplatform: {
+                        getApplication: function () {
+                            return mockApplication;
+                        }
+                    }
+                }
+            };
+
+        GLOBAL.window = mockWindow;
+
+        this.after(function () {
+            delete GLOBAL.window;
+        });
+
+        expect(utils.invokeInBrowser).toBeDefined();
+
+        utils.invokeInBrowser(url);
+
+        expect(mockApplication.invocation.invoke).toHaveBeenCalledWith({
+            uri: url,
+            target: "sys.browser"
+        });
+    });
+
+    // A cascading method invoker, kinda like jWorkflow
+    describe("series", function () {
+        var tasks,
+            callbackObj,
+            seriesComplete,
+            callbackInvocations,
+            invocationCounter,
+            task;
+
+        beforeEach(function () {
+            tasks = [];
+            callbackInvocations = [];
+            invocationCounter = 0;
+            seriesComplete = false;
+            callbackObj = {
+                func: function (args) {
+                    callbackInvocations.push('done');
+                    seriesComplete = true;
+                },
+                args: []
+            };
+            task = {
+                func: function (callback) {
+                    callbackInvocations.push(invocationCounter++);
+                    callback();
+                },
+                args: []
+            };
+        });
+
+        afterEach(function () {
+            tasks = null;
+            callbackObj = null;
+            seriesComplete = null;
+            callbackInvocations = null;
+            invocationCounter = null;
+            task = null;
+        });
+
+        it('should call callback right away when there are no tasks to execute', function () {
+            spyOn(callbackObj, 'func');
+            utils.series(tasks, callbackObj);
+            expect(callbackObj.func).toHaveBeenCalled();
+        });
+
+        it('should invoke the task method before the callback', function () {
+            tasks.push(task);
+            utils.series(tasks, callbackObj);
+            waitsFor(function () {
+                return seriesComplete;
+            });
+
+            expect(callbackInvocations.length).toEqual(2);
+            expect(callbackInvocations[0]).toEqual(0);
+            expect(callbackInvocations[1]).toEqual('done');
+        });
+
+        it('should invocation the tasks in order with the callback being the last invocation', function () {
+            var i;
+
+            tasks.push(task);
+            tasks.push(task);
+            tasks.push(task);
+            tasks.push(task);
+
+            utils.series(tasks, callbackObj);
+
+            waitsFor(function () {
+                return seriesComplete;
+            });
+
+            expect(callbackInvocations.length).toEqual(5);
+
+            for (i = 0; i < 4; i++) {
+                expect(callbackInvocations[i]).toEqual(i);
+            }
+
+            expect(callbackInvocations[4]).toEqual('done');
+        });
+    });
+
+    describe("utils translate path", function () {
+        beforeEach(function () {
+            GLOBAL.window = {
+                qnx: {
+                    webplatform: {
+                        getApplication: function () {
+                            return {
+                                getEnv: function (path) {
+                                    if (path === "HOME")
+                                        return "/accounts/home";
+                                }
+                            };
+                        }
+                    }
+                }
+            };
+        });
+
+        afterEach(function () {
+            delete GLOBAL.window;
+        });
+
+        it("Expect translate path to be defined", function () {
+            expect(utils.translatePath).toBeDefined();
+        });
+        it("translate path successfully returns the original path when passed non local value", function () {
+            var path = "http://google.com";
+            path = utils.translatePath(path);
+            expect(path).toEqual("http://google.com");
+        });
+        it("translate path successfully returns the original path when passed a telephone uri", function () {
+            var path = "tel://250-654-34243";
+            path = utils.translatePath(path);
+            expect(path).toEqual("tel://250-654-34243");
+        });
+        it("translate path successfully retuns an updated string for a local path", function () {
+            var path = "local:///this-is-a-local/img/path.jpg";
+            path = utils.translatePath(path);
+            expect(path).toEqual("file:///accounts/home/../app/native/this-is-a-local/img/path.jpg");
+        });
+    });
+
+    describe("deepclone", function () {
+        it("passes through null", function () {
+            expect(utils.deepclone(null)).toBe(null);
+        });
+
+        it("passes through undefined", function () {
+            expect(utils.deepclone(undefined)).toBe(undefined);
+        });
+
+        it("passes through a Number", function () {
+            expect(utils.deepclone(1)).toBe(1);
+        });
+
+        it("passes through a String", function () {
+            var str = "hello world";
+            expect(utils.deepclone(str)).toBe(str);
+        });
+
+        it("passes through a Boolean", function () {
+            expect(utils.deepclone(true)).toBe(true);
+            expect(utils.deepclone(false)).toBe(false);
+        });
+
+        it("returns a new Date", function () {
+            var date = new Date(),
+                dateCopy = utils.deepclone(date);
+
+            expect(dateCopy instanceof Date).toBe(true, "Not a Date");
+            expect(date).not.toBe(dateCopy);
+            expect(date.getTime()).toBe(dateCopy.getTime());
+        });
+
+        it("returns a new RegExp", function () {
+            var regex = /a/,
+                regexCopy = utils.deepclone(regex);
+
+            expect(regexCopy instanceof RegExp).toBe(true, "Not a RegExp");
+            expect(regexCopy).not.toBe(regex);
+            expect(regexCopy.toString()).toBe(regex.toString());
+        });
+
+        it("copies nested Object properties", function () {
+            var obj = {
+                    a: "hello world",
+                    b: "hello again"
+                },
+                objCopy = utils.deepclone(obj);
+
+            expect(obj).not.toBe(objCopy);
+            expect(obj).toEqual(objCopy);
+        });
+    });
+});

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/88ad654c/lib/cordova-blackberry/framework/test/unit/lib/webkitHandlers/networkResourceRequested.js
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/framework/test/unit/lib/webkitHandlers/networkResourceRequested.js b/lib/cordova-blackberry/framework/test/unit/lib/webkitHandlers/networkResourceRequested.js
new file mode 100644
index 0000000..efd4efe
--- /dev/null
+++ b/lib/cordova-blackberry/framework/test/unit/lib/webkitHandlers/networkResourceRequested.js
@@ -0,0 +1,167 @@
+describe("NetworkResourceRequested event handler", function () {
+    var LIB_PATH  = "./../../../../lib/",
+        networkResourceRequested = require(LIB_PATH + "webkitHandlers/networkResourceRequested"),
+        Whitelist = require(LIB_PATH + 'policy/whitelist').Whitelist,
+        server = require(LIB_PATH + 'server'),
+        utils = require(LIB_PATH + 'utils'),
+        mockedWebview;
+
+    beforeEach(function () {
+        mockedWebview = {
+            originalLocation : "http://www.origin.com",
+            executeJavaScript : jasmine.createSpy(),
+            id: 42,
+            uiWebView: {
+                childwebviewcontrols: {
+                    open: jasmine.createSpy()
+                }
+            }
+        };
+    });
+
+    afterEach(function () {
+        mockedWebview = undefined;
+    });
+
+    it("creates a callback for yous", function () {
+        var requestObj = networkResourceRequested.createHandler();
+        expect(requestObj.networkResourceRequestedHandler).toBeDefined();
+    });
+
+
+    it("can access the whitelist", function () {
+        spyOn(Whitelist.prototype, "isAccessAllowed").andReturn(true);
+        var url = "http://www.google.com",
+            requestObj = networkResourceRequested.createHandler(mockedWebview);
+        requestObj.networkResourceRequestedHandler(JSON.stringify({url: url}));
+        expect(Whitelist.prototype.isAccessAllowed).toHaveBeenCalled();
+    });
+
+    it("checks whether the request is for an iframe when accessing the whitelist", function () {
+        spyOn(Whitelist.prototype, "isAccessAllowed").andReturn(true);
+        var url = "http://www.google.com",
+            requestObj = networkResourceRequested.createHandler(mockedWebview);
+        requestObj.networkResourceRequestedHandler(JSON.stringify({url: url, targetType: "TargetIsXMLHTTPRequest"}));
+        expect(Whitelist.prototype.isAccessAllowed).toHaveBeenCalledWith(url, true);
+    });
+
+    it("can apply whitelist rules and allow valid urls", function () {
+        spyOn(Whitelist.prototype, "isAccessAllowed").andReturn(true);
+        var url = "http://www.google.com",
+            requestObj = networkResourceRequested.createHandler(mockedWebview),
+            returnValue = requestObj.networkResourceRequestedHandler(JSON.stringify({url: url}));
+        expect(Whitelist.prototype.isAccessAllowed).toHaveBeenCalled();
+        expect(JSON.parse(returnValue).setAction).toEqual("ACCEPT");
+    });
+
+    it("can apply whitelist rules and deny blocked urls", function () {
+        spyOn(Whitelist.prototype, "isAccessAllowed").andReturn(false);
+        spyOn(utils, "invokeInBrowser");
+        spyOn(console, "warn");
+
+        var url = "http://www.google.com",
+            requestObj = networkResourceRequested.createHandler(mockedWebview),
+            returnValue = requestObj.networkResourceRequestedHandler(JSON.stringify({url: url})),
+            deniedMsg = "Access to \"" + url + "\" not allowed";
+
+        expect(Whitelist.prototype.isAccessAllowed).toHaveBeenCalled();
+        expect(JSON.parse(returnValue).setAction).toEqual("DENY");
+        expect(utils.invokeInBrowser).not.toHaveBeenCalledWith(url);
+        expect(mockedWebview.uiWebView.childwebviewcontrols.open).not.toHaveBeenCalledWith(url);
+        expect(mockedWebview.executeJavaScript).toHaveBeenCalledWith("alert('" + deniedMsg + "')");
+        expect(console.warn).toHaveBeenCalledWith(deniedMsg);
+    });
+
+    it("can apply whitelist rules and deny blocked urls and route to a uiWebView when target is main frame", function () {
+        spyOn(Whitelist.prototype, "isAccessAllowed").andReturn(false);
+        spyOn(utils, "invokeInBrowser");
+        spyOn(console, "warn");
+
+        var url = "http://www.google.com",
+            requestObj = networkResourceRequested.createHandler(mockedWebview),
+            returnValue = requestObj.networkResourceRequestedHandler(JSON.stringify({url: url, targetType: "TargetIsMainFrame"})),
+            deniedMsg = "Access to \"" + url + "\" not allowed";
+
+        expect(Whitelist.prototype.isAccessAllowed).toHaveBeenCalled();
+        expect(mockedWebview.uiWebView.childwebviewcontrols.open).toHaveBeenCalledWith(url);
+        expect(mockedWebview.executeJavaScript).not.toHaveBeenCalledWith("alert('" + deniedMsg + "')");
+        expect(console.warn).toHaveBeenCalledWith(deniedMsg);
+        expect(utils.invokeInBrowser).not.toHaveBeenCalledWith(url);
+        expect(JSON.parse(returnValue).setAction).toEqual("DENY");
+    });
+
+    it("can apply whitelist rules and deny blocked urls and route to the browser when target is main frame and childWebView is disabled", function () {
+        var url = "http://www.google.com",
+            config = require(LIB_PATH + "config"),
+            deniedMsg = "Access to \"" + url + "\" not allowed",
+            requestObj,
+            returnValue;
+
+        spyOn(Whitelist.prototype, "isAccessAllowed").andReturn(false);
+        spyOn(utils, "invokeInBrowser");
+        spyOn(console, "warn");
+
+        config.enableChildWebView = false;
+
+        this.after(function () {
+            delete require.cache[require.resolve(LIB_PATH + "config")];
+        });
+
+        requestObj = networkResourceRequested.createHandler(mockedWebview);
+        returnValue = requestObj.networkResourceRequestedHandler(JSON.stringify({url: url, targetType: "TargetIsMainFrame"}));
+
+        expect(Whitelist.prototype.isAccessAllowed).toHaveBeenCalled();
+        expect(mockedWebview.uiWebView.childwebviewcontrols.open).not.toHaveBeenCalledWith(url);
+        expect(mockedWebview.executeJavaScript).not.toHaveBeenCalledWith("alert('" + deniedMsg + "')");
+        expect(console.warn).toHaveBeenCalledWith(deniedMsg);
+        expect(utils.invokeInBrowser).toHaveBeenCalledWith(url);
+        expect(JSON.parse(returnValue).setAction).toEqual("DENY");
+    });
+
+    it("can call the server handler when certain urls are detected", function () {
+        spyOn(server, "handle");
+        var url = "http://localhost:8472/roomService/kungfuAction/customExt/crystalMethod?blargs=yes",
+            requestObj = networkResourceRequested.createHandler(mockedWebview),
+            returnValue = requestObj.networkResourceRequestedHandler(JSON.stringify({url: url, referrer: "http://www.origin.com"})),
+            expectedRequest = {
+                params: {
+                    service: "roomService",
+                    action: "kungfuAction",
+                    ext: "customExt",
+                    method: "crystalMethod",
+                    args: "blargs=yes"
+                },
+                body: undefined,
+                origin: "http://www.origin.com"
+            },
+            expectedResponse = {
+                send: jasmine.any(Function)
+            };
+        expect(JSON.parse(returnValue).setAction).toEqual("SUBSTITUTE");
+        expect(server.handle).toHaveBeenCalledWith(expectedRequest, expectedResponse, mockedWebview);
+    });
+
+    it("can call the server handler correctly with a multi-level method", function () {
+        spyOn(server, "handle");
+        var url = "http://localhost:8472/roomService/kungfuAction/customExt/crystal/Method?blargs=yes",
+            requestObj = networkResourceRequested.createHandler(mockedWebview),
+            returnValue = requestObj.networkResourceRequestedHandler(JSON.stringify({url: url, referrer: "http://www.origin.com"})),
+            expectedRequest = {
+                params: {
+                    service: "roomService",
+                    action: "kungfuAction",
+                    ext: "customExt",
+                    method: "crystal/Method",
+                    args: "blargs=yes"
+                },
+                body: undefined,
+                origin: "http://www.origin.com"
+            },
+            expectedResponse = {
+                send: jasmine.any(Function)
+            };
+        expect(JSON.parse(returnValue).setAction).toEqual("SUBSTITUTE");
+        expect(server.handle).toHaveBeenCalledWith(expectedRequest, expectedResponse, mockedWebview);
+    });
+
+});

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/88ad654c/lib/cordova-blackberry/framework/test/unit/lib/webview.js
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/framework/test/unit/lib/webview.js b/lib/cordova-blackberry/framework/test/unit/lib/webview.js
new file mode 100644
index 0000000..e96eb18
--- /dev/null
+++ b/lib/cordova-blackberry/framework/test/unit/lib/webview.js
@@ -0,0 +1,334 @@
+describe("webview", function () {
+    var libPath = "./../../../lib/",
+        networkResourceRequested = require(libPath + "webkitHandlers/networkResourceRequested"),
+        webkitOriginAccess = require(libPath + "policy/webkitOriginAccess"),
+        webview,
+        mockedController,
+        mockedWebview,
+        mockedQnx,
+        globalCreate;
+
+    beforeEach(function () {
+        webview = require(libPath + "webview");
+        mockedController = {
+            enableWebInspector: undefined,
+            enableCrossSiteXHR: undefined,
+            visible: undefined,
+            active: undefined,
+            setGeometry: jasmine.createSpy(),
+            dispatchEvent : jasmine.createSpy(),
+            addEventListener : jasmine.createSpy()
+        };
+        mockedWebview = {
+            id: 42,
+            enableCrossSiteXHR: undefined,
+            visible: undefined,
+            active: undefined,
+            zOrder: undefined,
+            url: undefined,
+            reload: jasmine.createSpy(),
+            extraHttpHeaders: undefined,
+            setFileSystemSandbox: undefined,
+            addOriginAccessWhitelistEntry: jasmine.createSpy(),
+            setGeometry: jasmine.createSpy(),
+            setApplicationOrientation: jasmine.createSpy(),
+            setExtraPluginDirectory: jasmine.createSpy(),
+            setEnablePlugins: jasmine.createSpy(),
+            getEnablePlugins: jasmine.createSpy(),
+            notifyApplicationOrientationDone: jasmine.createSpy(),
+            onContextMenuRequestEvent: undefined,
+            onContextMenuCancelEvent: undefined,
+            onNetworkResourceRequested: undefined,
+            destroy: jasmine.createSpy(),
+            executeJavaScript: jasmine.createSpy(),
+            windowGroup: undefined,
+            addEventListener: jasmine.createSpy(),
+            enableWebEventRedirect: jasmine.createSpy(),
+            addKnownSSLCertificate: jasmine.createSpy(),
+            continueSSLHandshaking: jasmine.createSpy(),
+            setSensitivity: jasmine.createSpy(),
+            getSensitivity: jasmine.createSpy(),
+            setBackgroundColor: jasmine.createSpy(),
+            getBackgroundColor: jasmine.createSpy(),
+            allowWebEvent: jasmine.createSpy(),
+            allowUserMedia: jasmine.createSpy(),
+            disallowUserMedia: jasmine.createSpy()
+        };
+        mockedQnx = {
+            callExtensionMethod: jasmine.createSpy(),
+            webplatform: {
+                getController: function () {
+                    return mockedController;
+                },
+                createWebView: function (options, createFunction) {
+                    //process.nextTick(createFunction);
+                    //setTimeout(createFunction,0);
+                    if (typeof options === 'function') {
+                        runs(options);
+                        globalCreate = options;
+                    }
+                    else {
+                        runs(createFunction);
+                        globalCreate = createFunction;
+                    }
+                    return mockedWebview;
+                },
+                getApplication: jasmine.createSpy()
+            }
+        };
+        GLOBAL.qnx = mockedQnx;
+        GLOBAL.window = {
+            qnx: mockedQnx
+        };
+        GLOBAL.screen = {
+            width : 1024,
+            height: 768
+        };
+    });
+
+    afterEach(function () {
+        delete GLOBAL.qnx;
+        delete GLOBAL.window;
+        delete GLOBAL.screen;
+    });
+
+    describe("create", function () {
+        it("sets up the visible webview", function () {
+            var mockNetworkHandler = { networkResourceRequestedHandler: function onNetworkResourceRequested() {} };
+
+            spyOn(networkResourceRequested, "createHandler").andReturn(mockNetworkHandler);
+            spyOn(webkitOriginAccess, "addWebView");
+            webview.create();
+            waits(1);
+            runs(function () {
+                expect(mockedWebview.visible).toEqual(true);
+                expect(mockedWebview.active).toEqual(true);
+                expect(mockedWebview.zOrder).toEqual(0);
+                expect(mockedWebview.setGeometry).toHaveBeenCalledWith(0, 0, screen.width, screen.height);
+                expect(Object.getOwnPropertyDescriptor(webview, 'onContextMenuRequestEvent')).toEqual(jasmine.any(Object));
+                expect(Object.getOwnPropertyDescriptor(webview, 'onContextMenuCancelEvent')).toEqual(jasmine.any(Object));
+                expect(Object.getOwnPropertyDescriptor(webview, 'onGeolocationPermissionRequest')).toEqual(jasmine.any(Object));
+
+
+                expect(networkResourceRequested.createHandler).toHaveBeenCalledWith(mockedWebview);
+                expect(mockedWebview.onNetworkResourceRequested).toEqual(mockNetworkHandler.networkResourceRequestedHandler);
+
+                expect(mockedWebview.allowWebEvent).toHaveBeenCalledWith("DialogRequested");
+                expect(mockedController.dispatchEvent).toHaveBeenCalledWith("webview.initialized", jasmine.any(Array));
+                //The default config.xml only has access to WIDGET_LOCAL
+                //and has permission for two apis
+                expect(webkitOriginAccess.addWebView).toHaveBeenCalledWith(mockedWebview);
+            });
+        });
+
+        it("calls the ready function", function () {
+            var chuck = jasmine.createSpy();
+            webview.create(chuck);
+            waits(1);
+            runs(function () {
+                expect(chuck).toHaveBeenCalled();
+            });
+        });
+
+    });
+
+    describe("file system sandbox", function () {
+        it("setSandbox", function () {
+            webview.create();
+            webview.setSandbox(false);
+            expect(mockedWebview.setFileSystemSandbox).toBeFalsy();
+        });
+
+        it("getSandbox", function () {
+            webview.create();
+            webview.setSandbox(false);
+            expect(webview.getSandbox()).toBeFalsy();
+        });
+    });
+
+    describe("id", function () {
+        it("can get the id for the webiew", function () {
+            webview.create();
+            expect(webview.id).toEqual(mockedWebview.id);
+        });
+    });
+
+    describe("enableCrossSiteXHR", function () {
+        it("can set enableCrossSiteXHR", function () {
+            webview.create();
+            webview.enableCrossSiteXHR = true;
+            expect(mockedWebview.enableCrossSiteXHR).toBe(true);
+            webview.enableCrossSiteXHR = false;
+            expect(mockedWebview.enableCrossSiteXHR).toBe(false);
+        });
+    });
+
+    describe("geometry", function () {
+        it("can set geometry", function () {
+            webview.create();
+            webview.setGeometry(0, 0, 100, 200);
+            expect(mockedWebview.setGeometry).toHaveBeenCalledWith(0, 0, 100, 200);
+        });
+
+        it("can get geometry", function () {
+            webview.create();
+            webview.setGeometry(0, 0, 100, 100);
+            expect(webview.getGeometry()).toEqual({x: 0, y: 0, w: 100, h: 100});
+        });
+    });
+
+    describe("application orientation", function () {
+        it("can set application orientation", function () {
+            webview.create();
+            webview.setApplicationOrientation(90);
+            expect(mockedWebview.setApplicationOrientation).toHaveBeenCalledWith(90);
+        });
+
+        it("can notifyApplicationOrientationDone", function () {
+            webview.create();
+            webview.notifyApplicationOrientationDone();
+            expect(mockedWebview.notifyApplicationOrientationDone).toHaveBeenCalled();
+        });
+    });
+
+    describe("plugins", function () {
+        it("can set an extra plugin directory", function () {
+            webview.create();
+            webview.setExtraPluginDirectory('/usr/lib/browser/plugins');
+            expect(mockedWebview.setExtraPluginDirectory).toHaveBeenCalledWith('/usr/lib/browser/plugins');
+        });
+
+        it("can enable plugins for the webview", function () {
+            webview.create();
+            webview.setEnablePlugins(true);
+            expect(mockedWebview.pluginsEnabled).toBeTruthy();
+        });
+
+        it("can retrieve whether plugins are enabled", function () {
+            webview.create();
+            webview.setEnablePlugins(true);
+            expect(webview.getEnablePlugins()).toBeTruthy();
+        });
+    });
+
+    describe("SSL Exception Methods", function () {
+        it("addKnownSSLException", function () {
+            var url = 'https://bojaps.com',
+                certificateInfo = {
+                    test : 'test'
+                };
+            webview.create();
+            webview.addKnownSSLCertificate(url, certificateInfo);
+            expect(mockedWebview.addKnownSSLCertificate).toHaveBeenCalledWith(url, certificateInfo);
+        });
+
+        it("continue SSL Hanshaking", function () {
+            var streamId = 8,
+                SSLAction = 'SSLActionReject';
+            webview.create();
+            webview.continueSSLHandshaking(streamId, SSLAction);
+            expect(mockedWebview.continueSSLHandshaking).toHaveBeenCalledWith(streamId, SSLAction);
+        });
+    });
+
+    describe("User Media", function () {
+        it("has allowUserMedia defined", function () {
+            webview.create();
+            expect(webview.allowUserMedia).toBeDefined();
+        });
+
+        it("has disallowUserMedia defined", function () {
+            webview.create();
+            expect(webview.disallowUserMedia).toBeDefined();
+        });
+
+        it("calls allowUserMedia on WebView", function () {
+            var evtId = 10,
+                cameraName = "CAMERA_UNIT_FRONT";
+
+            webview.create();
+            webview.allowUserMedia(evtId, cameraName);
+            expect(mockedWebview.allowUserMedia).toHaveBeenCalledWith(evtId, cameraName);
+        });
+
+        it("calls disallowUserMedia on WebView", function () {
+            var evtId = 10;
+
+            webview.create();
+            webview.disallowUserMedia(evtId);
+            expect(mockedWebview.disallowUserMedia).toHaveBeenCalledWith(evtId);
+        });
+    });
+
+    describe("methods other than create", function () {
+
+        it("calls the underlying destroy", function () {
+            webview.create(mockedWebview);
+            webview.destroy();
+            expect(mockedWebview.destroy).toHaveBeenCalled();
+        });
+
+        it("sets the url property", function () {
+            var url = "http://AWESOMESAUCE.com";
+            webview.create(mockedWebview);
+            webview.setURL(url);
+            expect(mockedWebview.url).toEqual(url);
+        });
+
+        it("calls the underlying executeJavaScript", function () {
+            var js = "var awesome='Jasmine BDD'";
+            webview.create(mockedWebview);
+            webview.executeJavascript(js);
+            expect(mockedWebview.executeJavaScript).toHaveBeenCalledWith(js);
+        });
+        it("calls the underlying windowGroup property", function () {
+            webview.create(mockedWebview);
+            expect(webview.windowGroup()).toEqual(mockedWebview.windowGroup);
+        });
+
+        it("expect the config to set the extraHttpHeader", function () {
+            webview.create();
+            waits(1);
+            runs(function () {
+                expect(mockedWebview.extraHttpHeaders).toEqual({"rim-header": "RIM-Widget:rim/widget"});
+            });
+        });
+
+        it("expect the config to set the user agent", function () {
+            webview.create();
+            waits(1);
+            runs(function () {
+                expect(mockedWebview.userAgent).toEqual("Some extremely long user agent (with) spe/cial, characters");
+            });
+        });
+
+        it("expect reload to be defined", function () {
+            webview.create();
+            waits(1);
+            expect(webview.reload).toBeDefined();
+            webview.reload();
+            expect(mockedWebview.reload).toHaveBeenCalled();
+        });
+    });
+
+    describe("methods for sensitivity", function () {
+
+        it("setter getter for sensitivity", function () {
+            webview.create(mockedWebview);
+            webview.setSensitivity("Something");
+            expect(mockedWebview.setSensitivity).toHaveBeenCalled();
+            webview.getSensitivity();
+            expect(mockedWebview.getSensitivity).toHaveBeenCalled();
+        });
+
+        it("setter getter for background", function () {
+            webview.create(mockedWebview);
+            webview.setBackgroundColor("Something");
+            expect(mockedWebview.setBackgroundColor).toHaveBeenCalled();
+            webview.getBackgroundColor();
+            expect(mockedWebview.getBackgroundColor).toHaveBeenCalled();
+        });
+
+    });
+
+});