I am developing a testing framework for iOS development. I'd also like for this testing framework to be well-tested. The problem is, I can't figure out how to write a test for my test target that asserts my framework is correctly causing failed tests. If I create a failed test, I have in turn, caused the test to fail (I know, it's confusing).
Consider an example. Part of my framework includes function to verify that a particular code snippet does not have any breaking constraints.
MTKAssertNoBrokenConstraints {
// UI code that might break some constraints
}
I have tested this by hand to verify that when there are no broken constraints, the assertion passes, but when there are broken constraints, it correctly marks the test as failing.
But I need a way to verify that MTKAssertNoBrokenConstraints would mark a test as failing without actually marking the test for this itself as failing.
I have looked into creating a custom object that conforms to XCTestObservation, but so far I've only ended up with infinite recursion. I'm not sure whether this is the right path, or whether resolving the infinite recursion will actually get me where I need to be.
The following test intercepts the failure of XCTFail("FOO") and then performs some checks against the failure.
class TestTheTests: XCTestCase {
var interceptFailure = false
var failureCount = 0
var failureDescription = ""
var failureFilePath = ""
var failureLineNumber: UInt = 0
var failureExpected = false
override func recordFailureWithDescription(description: String, inFile filePath: String, atLine lineNumber: UInt, expected: Bool) {
if !interceptFailure {
super.recordFailureWithDescription(description, inFile: filePath, atLine: lineNumber, expected: expected)
} else {
failureCount += 1
failureDescription = description
failureFilePath = filePath
failureLineNumber = lineNumber
failureExpected = expected
}
}
func testExample() {
interceptFailure = true
XCTFail("FOO")
interceptFailure = false
XCTAssertEqual(failureCount, 1)
XCTAssertTrue(failureDescription.hasSuffix("FOO"), "Was \"\(failureDescription)\"")
}
}
Related
new approach to ask my question. I thought it was clear but apparently
not. :-D 2nd chance.
I use SWXMLhash to get information from websites. For each website i need a different struct, because the datastructure of each website is different.
I have a good working function (using 1 website as source) which i would like to transform to a general function depending on the chosen website.
The best solution i have got so far (see code below) got me a compile error on:
TorrentProviderItem = try xmlTorrent["rss"]["channel"]["item"].value()
compile error = Ambiguous reference to member 'subscript'
code of function:
private func setResultsToEqualData(result: String, Torrentprovider: TorrentProviders) {
var TorrentProviderItem: [XMLIndexerDeserializable]
var xmlTorrent: XMLIndexer!
xmlTorrent = SWXMLHash.parse(result)
switch Torrentprovider {
case .ExtraTorrent:
TorrentProviderItem = [ExtraTorrentItem]()
default:
TorrentProviderItem = [Torrentz2Item]()
}
do {
TorrentProviderItem = try xmlTorrent["rss"]["channel"]["item"].value()
} catch {
print("FOUT in torrent!!")
return
}
selectBestResult()
}
I have no clue how to fix this. Anyone else?
ps in the original function for 1 website i use:
var TorrentProviderItem: [ExtraTorrentItem]
and without the switch, that works fine.
Some showed me the options of a function within a struct. So i used this to build a workaround. I wrote a function in each struct for each website, the returning value of each function is of the same datatype.
For me it is a workaround and not the solution. I still have to add every website to the function (see below).
private func setResultsToEqualData(result: String, Torrentprovider: TorrentProviders) -> torrentProviderItem? {
var TorrentProviderItem = [torrentProviderItem]()
var xmlTorrent: XMLIndexer!
xmlTorrent = SWXMLHash.parse(result)
switch Torrentprovider {
case .ExtraTorrent:
var tempExtraTorrentItem: [ExtraTorrentItem]
do {
tempExtraTorrentItem = try xmlTorrent["rss"]["channel"]["item"].value()
for item in tempExtraTorrentItem {
TorrentProviderItem.append(item.result())
}
} catch {
print("FOUT in torrent!!")
return nil
}
case .Torrentz2:
var tempTorrentz2Item: [Torrentz2Item]
do {
tempTorrentz2Item = try xmlTorrent["rss"]["channel"]["item"].value()
for item in tempTorrentz2Item {
TorrentProviderItem.append(item.result())
}
} catch {
print("FOUT in torrent!!")
return nil
}
}
return (selectBestResult(results: TorrentProviderItem))
}
I think the solution to create a general function lay's within the Strucs. To use one struct for all websites in stead of a struct for each website. I just don't know how to do this. Jet.
I am trying to print an enum (or structure) using fmt::Display. Though the code compiles and gets to the display method, it doesn't print the value.
pub enum TestEnum<'a> {
Foo(&'a str),
Bar(f32)
}
impl<'b> fmt::Display for TestEnum <'b> {
fn fmt(&self, f : &mut fmt::Formatter) -> fmt::Result {
println!("Got this far");
match self{
&TestEnum::Foo(x) => write!(f,"{}",x),
&TestEnum::Bar(x) => write!(f,"{}",x),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_print() {
let cell = TestEnum::Str("foo");
println!("Printing");
println!("{}",cell); // No output here
}
}
I tried using {:?} and {} but to no avail.
This happens because Rust test program hides stdout of successful tests. You can disable this behavior passing --nocapture option to test binary or to cargo test command this way:
cargo test -- --nocapture
PS: your code is broken/incomplete
The test runner seems to divert the standard output; you should consider using assert!, assert_eq! or other panicky ways to test your assertions rather than printing in tests.
Besides, your code fails to compile due to mismatching names. I got it working as expected from main:
use std::fmt;
pub enum TestEnum<'a> {
Foo(&'a str),
Bar(f32)
}
impl<'b> fmt::Display for TestEnum <'b> {
fn fmt(&self, f : &mut fmt::Formatter) -> fmt::Result {
match self {
&TestEnum::Foo(x) => write!(f, "{}", x),
&TestEnum::Bar(x) => write!(f, "{}", x),
}
}
}
fn main() {
let cell = TestEnum::Foo("foo");
println!("Printing");
println!("{}", cell);
}
Test output is redirected to a buffer when the test succeeds as to not mangle up with the test "FAILED" or "ok" messages.
If you just want to test something while developing your test, you can always add a panic!() at the end of your test to make sure it keeps failing and outputting all logging. Or as #AndreaP notes in his answer, you can use cargo test -- --nocapture to display the standard output of all tests.
Usually a test should not write to stdout, but instead write to a buffer and check whether that buffer contains what it should:
let cell = TestEnum::Foo("foo");
let mut buf = Vec::new();
let _ = write!(buf, "{}\n", cell);
assert_eq!(&buf, b"foo\n");
If you truly want to output something, you need to write directly to stdout.
let _ = write!(io::stdout(), "{}\n", cell);
but this will mix with the test's output:
test tests::blub ... foo
ok
PlayPen
I'm trying to load a custom module in a restartless add-on, using the following:
chrome/content/modules/Test.jsm:
var EXPORTED_SYMBOLS = [ 'Test' ];
let Test = {};
chrome.manifest:
content test chrome/content/
bootstrap.js:
const Cu = Components.utils;
// Tried this first, but figured perhaps chrome directives aren't loaded here yet
// let test = Cu.import( 'chrome://test/modules/Test.jsm', {} ).Test;
function install() {
let test = Cu.import( 'chrome://test/modules/Test.jsm', {} ).Test;
}
function uninstall() {
let test = Cu.import( 'chrome://test/modules/Test.jsm', {} ).Test;
}
function startup() {
let test = Cu.import( 'chrome://test/modules/Test.jsm', {} ).Test;
}
function shutdown() {
let test = Cu.import( 'chrome://test/modules/Test.jsm', {} ).Test;
}
However, I get the following types of WARN messages (this one was for shutdown(), but basically identical for all functions and in the earlier attempt in the global scope):
1409229174591 addons.xpi WARN Exception running bootstrap method
shutdown on test#extensions.codifier.nl: [Exception... "Component
returned failure code: 0x80070057 (NS_ERROR_ILLEGAL_VALUE)
[nsIXPCComponents_Utils.import]" nsresult: "0x80070057
(NS_ERROR_ILLEGAL_VALUE)" location: "JS frame ::
resource://gre/modules/addons/XPIProvider.jsm ->
file:///test/bootstrap.js :: shutdown :: line 21" data: no] Stack
trace: shutdown()#resource://gre/modules/addons/XPIProvider.jsm ->
file:///test/bootstrap.js:21 <
XPI_callBootstrapMethod()#resource://gre/modules/addons/XPIProvider.jsm:4232
<
XPI_updateAddonDisabledState()#resource://gre/modules/addons/XPIProvider.jsm:4347
<
AddonWrapper_userDisabledSetter()#resource://gre/modules/addons/XPIProvider.jsm:6647
< uninstall()#extensions.xml:1541 < oncommand()#about:addons:1 <
Are chrome.manifest directives not yet available in bootstrap.js? Or is what I am attempting some kind of security violation, perhaps? Or am I simply doing something trivially wrong?
What I was hoping to achieve, is that I could do something like the following:
chrome/content/modules/Test.jsm:
var EXPORTED_SYMBOLS = [ 'Test' ];
let Test = {
install: function( data, reason ) {
},
/* etc */
bootstrap: function( context ) {
context.install = this.install;
context.uninstall = this.uninstall;
context.startup = this.startup;
context.shutdown = this.shutdown;
}
}
bootstrap.js:
const Cu = Components.utils;
Cu.import( 'chrome://test/modules/Test.jsm' );
Test.bootstrap( this );
Perhaps it's a bit over the top to begin with, but I just kind of like the idea of hiding implementations in modules and/or objects and keeping bootstrap.js super clean.
If you happen to have suggestions on how to achieve this by other means: I'm all ears.
Yes you can your path is wrong though.
Just do this:
let test = Cu.import( 'chrome://test/content/modules/Test.jsm', {} ).Test;
notice the /content/
You don't have to do the .Test unless you want the lower case test to hold it. You can just do:
Cu.import( 'chrome://test/content/modules/Test.jsm');
and use as Test.blah where blah is whatever is in the JSM module.
This code can go anywhere, it does not have to be in the install function.
Make sure to unload the custom JSM modules or else it can lead to zombie compartments which is bad for memory. Read here:
last paragraph here: https://developer.mozilla.org/en-US/docs/Extensions/Common_causes_of_memory_leaks_in_extensions
more reading but optional: https://developer.mozilla.org/en-US/docs/Zombie_compartments
Beyond #Noitidart's answer, you don't have to use chrome.manifest' and register a content package if your only concern is how to import your module.
function install(data, reason) {
Components.utils.import(data.resourceURI.spec + "relative/path/to/your/module.jsm");
}
I am creating a firefox addon using the SDK. My goal is simple, to intercept a specific iframe and load my own HTML page (packaged as a resource with my addon) instead of the content that was requested originally.
So far I have the following code:
var httpRequestObserver =
{
observe: function(subject, topic, data)
{
var httpChannel, requestURL;
if (topic == "http-on-modify-request") {
httpChannel = subject.QueryInterface(Ci.nsIHttpChannel);
requestURL = httpChannel.URI.spec;
var newRequestURL, i;
if (/someurl/.test(requestURL)) {
var ioService = Cc["#mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
httpChannel.redirectTo(ioService.newURI(self.data.url('pages/test.html'), undefined, undefined));
}
return;
}
}
};
var observerService = Cc["#mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
observerService.addObserver(httpRequestObserver, "http-on-modify-request", false);
This code works in that it detects the proper iframe loading and does the redirect correctly. However, I get the following error:
Security Error: Content at http://url.com may not load or link to
jar:file:///.../pages/test.html.
How can I get around this limitation?
actually man i was really over thinking this.
its already solved when I changed to using loadContext. Now when you get loadContext you get the contentWindow of whatever browser element (tab browser, or frame or iframe) and then just abort the http request like you are doing and then loadContext.associatedWindow.document.location = self.data('pages/tests.html');
done
ill paste the code here removing all the private stuff. you might need the chrome.manifest ill test it out and paste the code back here
Cu.import('resource://gre/modules/Services.jsm');
var httpRequestObserver = {
observe: function (subject, topic, data) {
var httpChannel, requestURL;
if (topic == "http-on-modify-request") {
httpChannel = subject.QueryInterface(Ci.nsIHttpChannel);
requestURL = httpChannel.URI.spec;
var newRequestURL, i;
if (/someurl/.test(requestURL)) {
var goodies = loadContextGoodies(httpChannel);
if (goodies) {
httpChannel.cancel(Cr.NS_BINDING_ABORTED);
goodies.contentWindow.location = self.data.url('pages/test.html');
} else {
//dont do anything as there is no contentWindow associated with the httpChannel, liekly a google ad is loading or some ajax call or something, so this is not an error
}
}
return;
}
}
};
Services.obs.addObserver(httpRequestObserver, "http-on-modify-request", false);
//this function gets the contentWindow and other good stuff from loadContext of httpChannel
function loadContextGoodies(httpChannel) {
//httpChannel must be the subject of http-on-modify-request QI'ed to nsiHTTPChannel as is done on line 8 "httpChannel = subject.QueryInterface(Ci.nsIHttpChannel);"
//start loadContext stuff
var loadContext;
try {
var interfaceRequestor = httpChannel.notificationCallbacks.QueryInterface(Ci.nsIInterfaceRequestor);
//var DOMWindow = interfaceRequestor.getInterface(Components.interfaces.nsIDOMWindow); //not to be done anymore because: https://developer.mozilla.org/en-US/docs/Updating_extensions_for_Firefox_3.5#Getting_a_load_context_from_a_request //instead do the loadContext stuff below
try {
loadContext = interfaceRequestor.getInterface(Ci.nsILoadContext);
} catch (ex) {
try {
loadContext = subject.loadGroup.notificationCallbacks.getInterface(Ci.nsILoadContext);
} catch (ex2) {}
}
} catch (ex0) {}
if (!loadContext) {
//no load context so dont do anything although you can run this, which is your old code
//this probably means that its loading an ajax call or like a google ad thing
return null;
} else {
var contentWindow = loadContext.associatedWindow;
if (!contentWindow) {
//this channel does not have a window, its probably loading a resource
//this probably means that its loading an ajax call or like a google ad thing
return null;
} else {
var aDOMWindow = contentWindow.top.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShellTreeItem)
.rootTreeItem
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindow);
var gBrowser = aDOMWindow.gBrowser;
var aTab = gBrowser._getTabForContentWindow(contentWindow.top); //this is the clickable tab xul element, the one found in the tab strip of the firefox window, aTab.linkedBrowser is same as browser var above //can stylize tab like aTab.style.backgroundColor = 'blue'; //can stylize the tab like aTab.style.fontColor = 'red';
var browser = aTab.linkedBrowser; //this is the browser within the tab //this is where the example in the previous section ends
return {
aDOMWindow: aDOMWindow,
gBrowser: gBrowser,
aTab: aTab,
browser: browser,
contentWindow: contentWindow
};
}
}
//end loadContext stuff
}
NOTE: Now try this first, I didn't test it yet, if you get a security error when it tries to redirect then create a chrome.manifest file and put it in the root directory. If it throws a security error than you definitely need a chrome.manifest file and that will without question fix it up. I'll test this myself later tonight when I get some time.
The chrome.manifest should look like this:
content kaboom-data ./resources/kaboom/data/ contentaccessible=yes
Then in the code way above change the redirect line from goodies.contentWindow.location = self.data.url('pages/test.html'); to goodies.contentWindow.location = 'chrome://kaboom-data/pages/test.html');.
see this addon here: https://addons.mozilla.org/en-US/firefox/addon/ghforkable/?src=search
in the chrome.manifest file we set the contentaccessible parameter to yes
you dont need sdk for this addon. its so simple, just ocpy paste that into a bootstrap skeleton as seen here:
Bootstrap With Some Features, Like chrome.manifest which you will need
Bootstrap Ultra Basic
if you want to really do a redirect of a page to your site, maybe you want to make a custom about page? if you would like ill throw togather a demo for you on making a custom about page. you can see a bit hard to understand demo here
posting my trials here so it can help all:
trail 1 failed - created chrome.manifest file with contents content kaboom-data resources/kaboom/data/ contentaccessible=yes
var myuri = Services.io.newURI('chrome://kaboom-data/content/pages/test.html', undefined, undefined);
httpChannel.redirectTo(myuri);
Error Thrown
Security Error: Content at http://digg.com/tools/diggthis/confirm? may
not load or link to
jar:file:///C:/Documents%20and%20Settings/SONY%20VAIO/Application%20Data/Mozilla/Firefox/Profiles/vr10qb8s.default/extensions/jid1-g4RtC8vdvPagpQ#jetpack.xpi!/resources/kaboom/data/pages/test.html.
trial 2 failed - created resource in bootstrap.js
alias.spec =
file:///C:/Documents%20and%20Settings/SONY%20VAIO/Application%20Data/Mozilla/Firefox/Profiles/vr10qb8s.default/extensions/jid1-g4RtC8vdvPagpQ#jetpack.xpi
alias updated to spec:
jar:file:///C:/Documents%20and%20Settings/SONY%20VAIO/Application%20Data/Mozilla/Firefox/Profiles/vr10qb8s.default/extensions/jid1-g4RtC8vdvPagpQ#jetpack.xpi!/
let resource = Services.io.getProtocolHandler("resource").QueryInterface(Ci.nsIResProtocolHandler);
let alias = Services.io.newFileURI(data.installPath);
Cu.reportError('alias.spec = ' + alias.spec);
if (!data.installPath.isDirectory()) {
alias = Services.io.newURI("jar:" + alias.spec + "!/", null, null);
Cu.reportError('alias updated to spec: ' + alias.spec);
}
resource.setSubstitution("kaboom_data", alias);
...
var myuri = Services.io.newURI('resource://kaboom_data/resources/kaboom/data/pages/test.html', undefined, undefined);
httpChannel.redirectTo(myuri);
Error Thrown
Security Error: Content at http://digg.com/tools/diggthis/confirm? may
not load or link to
jar:file:///C:/Documents%20and%20Settings/SONY%20VAIO/Application%20Data/Mozilla/Firefox/Profiles/vr10qb8s.default/extensions/jid1-g4RtC8vdvPagpQ#jetpack.xpi!/resources/kaboom/data/pages/test.html.
CONCLUSION
in both trials above it was the weirdest thing, it wouldnt show the resource or chrome path in the security error thrown but it would give the full jar path. Leading me to believe that this has something to do with redirectTo function.
The solution that did work was your solution of
var gBrowser = utils.getMostRecentBrowserWindow().gBrowser;
var domWin = httpChannel.notificationCallbacks.getInterface(Ci.nsIDOMWindow);
var browser = gBrowser.getBrowserForDocument(domWin.document);
//redirect
browser.loadURI(self.data.url('pages/test.html'));
however I changed this to use loadContext instead of this method because it is the recommended way. also gBrowser to getMostRecentBrowserWindow will fail if the url load is slow and in that time the user swithces to another tab or window
I also changed to use Services.jsm as you had imported Cu anyways. Using Services.jsm is super fast not even blink fast. Its just a pointer.
Im still working on trying to the redirectTo method working its really bothering me. The changes I made are to my local copy.
Have you considered turning your local HTML file into a data URL and loading that?
I have a service in my application which return a list of tracks, here is the code for that
List<Track> getTrackListTracks(String listName, int max) {
def tracks = getTrackListTracks(listName)
if(tracks?.size() > max) {
tracks = tracks[0 ..< max]
}
return tracks
}
List<Track> getTrackListTracks(String listName) {
def tl = TrackList.findByName(listName)
if(tl?.tracks) {
return tl?.tracks?.collect { Track.read(it.trackId) }
}
}
i have to write the unit test for this but I am not able to write. Can anyone help me in this.
Thanks Already
Hopefully you've progressed beyond this, but for those coming after, the grails-spock-examples project # google code (https://github.com/pschneider-manzell/grails-spock-examples) has a wide range of examples.
More specifically, for a service (as you've asked), check out Testing Services.
Caution, though - there are a few differences between that and what is required for Grails 2. For example, if testing controllers, 'redirectArgs' is no longer valid. Make sure to also consult the Grails Documentation for differences.