diff options
Diffstat (limited to 'image/test/unit/test_imgtools.js')
-rw-r--r-- | image/test/unit/test_imgtools.js | 737 |
1 files changed, 737 insertions, 0 deletions
diff --git a/image/test/unit/test_imgtools.js b/image/test/unit/test_imgtools.js new file mode 100644 index 000000000..b9b8da82b --- /dev/null +++ b/image/test/unit/test_imgtools.js @@ -0,0 +1,737 @@ +/* + * Tests for imgITools + */ + +var Ci = Components.interfaces; +var Cc = Components.classes; + + +/* + * dumpToFile() + * + * For test development, dumps the specified array to a file. + * Call |dumpToFile(outData);| in a test to file to a file. + */ +function dumpToFile(aData) { + var outputFile = do_get_tempdir(); + outputFile.append("testdump.png"); + + var outputStream = Cc["@mozilla.org/network/file-output-stream;1"]. + createInstance(Ci.nsIFileOutputStream); + // WR_ONLY|CREAT|TRUNC + outputStream.init(outputFile, 0x02 | 0x08 | 0x20, 0o644, null); + + var bos = Cc["@mozilla.org/binaryoutputstream;1"]. + createInstance(Ci.nsIBinaryOutputStream); + bos.setOutputStream(outputStream); + + bos.writeByteArray(aData, aData.length); + + outputStream.close(); +} + + +/* + * getFileInputStream() + * + * Returns an input stream for the specified file. + */ +function getFileInputStream(aFile) { + var inputStream = Cc["@mozilla.org/network/file-input-stream;1"]. + createInstance(Ci.nsIFileInputStream); + // init the stream as RD_ONLY, -1 == default permissions. + inputStream.init(aFile, 0x01, -1, null); + + // Blah. The image decoders use ReadSegments, which isn't implemented on + // file input streams. Use a buffered stream to make it work. + var bis = Cc["@mozilla.org/network/buffered-input-stream;1"]. + createInstance(Ci.nsIBufferedInputStream); + bis.init(inputStream, 1024); + + return bis; +} + + +/* + * streamToArray() + * + * Consumes an input stream, and returns its bytes as an array. + */ +function streamToArray(aStream) { + var size = aStream.available(); + + // use a binary input stream to grab the bytes. + var bis = Cc["@mozilla.org/binaryinputstream;1"]. + createInstance(Ci.nsIBinaryInputStream); + bis.setInputStream(aStream); + + var bytes = bis.readByteArray(size); + if (size != bytes.length) + throw "Didn't read expected number of bytes"; + + return bytes; +} + + +/* + * compareArrays + * + * Compares two arrays, and throws if there's a difference. + */ +function compareArrays(aArray1, aArray2) { + do_check_eq(aArray1.length, aArray2.length); + + for (var i = 0; i < aArray1.length; i++) + if (aArray1[i] != aArray2[i]) + throw "arrays differ at index " + i; +} + + +/* + * checkExpectedError + * + * Checks to see if a thrown error was expected or not, and if it + * matches the expected value. + */ +function checkExpectedError (aExpectedError, aActualError) { + if (aExpectedError) { + if (!aActualError) + throw "Didn't throw as expected (" + aExpectedError + ")"; + + if (!aExpectedError.test(aActualError)) + throw "Threw (" + aActualError + "), not (" + aExpectedError; + + // We got the expected error, so make a note in the test log. + dump("...that error was expected.\n\n"); + } else if (aActualError) { + throw "Threw unexpected error: " + aActualError; + } +} + + +function run_test() { + +try { + + +/* ========== 0 ========== */ +var testnum = 0; +var testdesc = "imgITools setup"; +var err = null; + +var imgTools = Cc["@mozilla.org/image/tools;1"]. + getService(Ci.imgITools); + +if (!imgTools) + throw "Couldn't get imgITools service" + +// Ugh, this is an ugly hack. The pixel values we get in Windows are sometimes +// +/- 1 value compared to other platforms, so we need to compare against a +// different set of reference images. nsIXULRuntime.OS doesn't seem to be +// available in xpcshell, so we'll use this as a kludgy way to figure out if +// we're running on Windows. +var isWindows = mozinfo.os == "win"; + + +/* ========== 1 ========== */ +testnum++; +testdesc = "test decoding a PNG"; + +// 64x64 png, 8415 bytes. +var imgName = "image1.png"; +var inMimeType = "image/png"; +var imgFile = do_get_file(imgName); + +var istream = getFileInputStream(imgFile); +do_check_eq(istream.available(), 8415); + +// Use decodeImageData for this test even though it's deprecated to ensure that +// it correctly forwards to decodeImage and continues to work. +var outParam = { value: null }; +imgTools.decodeImageData(istream, inMimeType, outParam); +var container = outParam.value; + +// It's not easy to look at the pixel values from JS, so just +// check the container's size. +do_check_eq(container.width, 64); +do_check_eq(container.height, 64); + + +/* ========== 2 ========== */ +testnum++; +testdesc = "test encoding a scaled JPEG"; + +// we'll reuse the container from the previous test +istream = imgTools.encodeScaledImage(container, "image/jpeg", 16, 16); + +var encodedBytes = streamToArray(istream); +// Get bytes for exected result +var refName = "image1png16x16.jpg"; +var refFile = do_get_file(refName); +istream = getFileInputStream(refFile); +do_check_eq(istream.available(), 1051); +var referenceBytes = streamToArray(istream); + +// compare the encoder's output to the reference file. +compareArrays(encodedBytes, referenceBytes); + + +/* ========== 3 ========== */ +testnum++; +testdesc = "test encoding an unscaled JPEG"; + +// we'll reuse the container from the previous test +istream = imgTools.encodeImage(container, "image/jpeg"); +encodedBytes = streamToArray(istream); + +// Get bytes for exected result +refName = "image1png64x64.jpg"; +refFile = do_get_file(refName); +istream = getFileInputStream(refFile); +do_check_eq(istream.available(), 4503); +referenceBytes = streamToArray(istream); + +// compare the encoder's output to the reference file. +compareArrays(encodedBytes, referenceBytes); + + +/* ========== 4 ========== */ +testnum++; +testdesc = "test decoding a JPEG"; + +// 32x32 jpeg, 3494 bytes. +imgName = "image2.jpg"; +inMimeType = "image/jpeg"; +imgFile = do_get_file(imgName); + +istream = getFileInputStream(imgFile); +do_check_eq(istream.available(), 3494); + +container = imgTools.decodeImage(istream, inMimeType); + +// It's not easy to look at the pixel values from JS, so just +// check the container's size. +do_check_eq(container.width, 32); +do_check_eq(container.height, 32); + + +/* ========== 5 ========== */ +testnum++; +testdesc = "test encoding a scaled PNG"; + +if (!isWindows) { +// we'll reuse the container from the previous test +istream = imgTools.encodeScaledImage(container, "image/png", 16, 16); + +encodedBytes = streamToArray(istream); +// Get bytes for exected result +refName = isWindows ? "image2jpg16x16-win.png" : "image2jpg16x16.png"; +refFile = do_get_file(refName); +istream = getFileInputStream(refFile); +do_check_eq(istream.available(), 950); +referenceBytes = streamToArray(istream); + +// compare the encoder's output to the reference file. +compareArrays(encodedBytes, referenceBytes); +} + + +/* ========== 6 ========== */ +testnum++; +testdesc = "test encoding an unscaled PNG"; + +if (!isWindows) { +// we'll reuse the container from the previous test +istream = imgTools.encodeImage(container, "image/png"); +encodedBytes = streamToArray(istream); + +// Get bytes for exected result +refName = isWindows ? "image2jpg32x32-win.png" : "image2jpg32x32.png"; +refFile = do_get_file(refName); +istream = getFileInputStream(refFile); +do_check_eq(istream.available(), 3105); +referenceBytes = streamToArray(istream); + +// compare the encoder's output to the reference file. +compareArrays(encodedBytes, referenceBytes); +} + + +/* ========== 7 ========== */ +testnum++; +testdesc = "test decoding a ICO"; + +// 16x16 ico, 1406 bytes. +imgName = "image3.ico"; +inMimeType = "image/x-icon"; +imgFile = do_get_file(imgName); + +istream = getFileInputStream(imgFile); +do_check_eq(istream.available(), 1406); + +container = imgTools.decodeImage(istream, inMimeType); + +// It's not easy to look at the pixel values from JS, so just +// check the container's size. +do_check_eq(container.width, 16); +do_check_eq(container.height, 16); + + +/* ========== 8 ========== */ +testnum++; +testdesc = "test encoding a scaled PNG"; // note that we're scaling UP + +// we'll reuse the container from the previous test +istream = imgTools.encodeScaledImage(container, "image/png", 32, 32); +encodedBytes = streamToArray(istream); + +// Get bytes for exected result +refName = "image3ico32x32.png"; +refFile = do_get_file(refName); +istream = getFileInputStream(refFile); +do_check_eq(istream.available(), 2285); +referenceBytes = streamToArray(istream); + +// compare the encoder's output to the reference file. +compareArrays(encodedBytes, referenceBytes); + + +/* ========== 9 ========== */ +testnum++; +testdesc = "test encoding an unscaled PNG"; + +// we'll reuse the container from the previous test +istream = imgTools.encodeImage(container, "image/png"); +encodedBytes = streamToArray(istream); + +// Get bytes for exected result +refName = "image3ico16x16.png"; +refFile = do_get_file(refName); +istream = getFileInputStream(refFile); +do_check_eq(istream.available(), 330); +referenceBytes = streamToArray(istream); + +// compare the encoder's output to the reference file. +compareArrays(encodedBytes, referenceBytes); + + +/* ========== 10 ========== */ +testnum++; +testdesc = "test decoding a GIF"; + +// 32x32 gif, 1809 bytes. +imgName = "image4.gif"; +inMimeType = "image/gif"; +imgFile = do_get_file(imgName); + +istream = getFileInputStream(imgFile); +do_check_eq(istream.available(), 1809); + +container = imgTools.decodeImage(istream, inMimeType); + +// It's not easy to look at the pixel values from JS, so just +// check the container's size. +do_check_eq(container.width, 32); +do_check_eq(container.height, 32); + +/* ========== 11 ========== */ +testnum++; +testdesc = "test encoding an unscaled ICO with format options " + + "(format=bmp;bpp=32)"; + +// we'll reuse the container from the previous test +istream = imgTools.encodeImage(container, + "image/vnd.microsoft.icon", + "format=bmp;bpp=32"); +encodedBytes = streamToArray(istream); + +// Get bytes for exected result +refName = "image4gif32x32bmp32bpp.ico"; +refFile = do_get_file(refName); +istream = getFileInputStream(refFile); +do_check_eq(istream.available(), 4286); +referenceBytes = streamToArray(istream); + +// compare the encoder's output to the reference file. +compareArrays(encodedBytes, referenceBytes); + +/* ========== 12 ========== */ +testnum++; +testdesc = "test encoding a scaled ICO with format options " + + "(format=bmp;bpp=32)"; + +// we'll reuse the container from the previous test +istream = imgTools.encodeScaledImage(container, + "image/vnd.microsoft.icon", + 16, + 16, + "format=bmp;bpp=32"); +encodedBytes = streamToArray(istream); + +// Get bytes for exected result +refName = "image4gif16x16bmp32bpp.ico"; +refFile = do_get_file(refName); +istream = getFileInputStream(refFile); +do_check_eq(istream.available(), 1150); +referenceBytes = streamToArray(istream); + +// compare the encoder's output to the reference file. +compareArrays(encodedBytes, referenceBytes); + +/* ========== 13 ========== */ +testnum++; +testdesc = "test encoding an unscaled ICO with format options " + + "(format=bmp;bpp=24)"; + +// we'll reuse the container from the previous test +istream = imgTools.encodeImage(container, + "image/vnd.microsoft.icon", + "format=bmp;bpp=24"); +encodedBytes = streamToArray(istream); + +// Get bytes for exected result +refName = "image4gif32x32bmp24bpp.ico"; +refFile = do_get_file(refName); +istream = getFileInputStream(refFile); +do_check_eq(istream.available(), 3262); +referenceBytes = streamToArray(istream); + +// compare the encoder's output to the reference file. +compareArrays(encodedBytes, referenceBytes); + +/* ========== 14 ========== */ +testnum++; +testdesc = "test encoding a scaled ICO with format options " + + "(format=bmp;bpp=24)"; + +// we'll reuse the container from the previous test +istream = imgTools.encodeScaledImage(container, + "image/vnd.microsoft.icon", + 16, + 16, + "format=bmp;bpp=24"); +encodedBytes = streamToArray(istream); + +// Get bytes for exected result +refName = "image4gif16x16bmp24bpp.ico"; +refFile = do_get_file(refName); +istream = getFileInputStream(refFile); +do_check_eq(istream.available(), 894); +referenceBytes = streamToArray(istream); + +// compare the encoder's output to the reference file. +compareArrays(encodedBytes, referenceBytes); + + +/* ========== 15 ========== */ +testnum++; +testdesc = "test cropping a JPG"; + +// 32x32 jpeg, 3494 bytes. +imgName = "image2.jpg"; +inMimeType = "image/jpeg"; +imgFile = do_get_file(imgName); + +istream = getFileInputStream(imgFile); +do_check_eq(istream.available(), 3494); + +container = imgTools.decodeImage(istream, inMimeType); + +// It's not easy to look at the pixel values from JS, so just +// check the container's size. +do_check_eq(container.width, 32); +do_check_eq(container.height, 32); + +// encode a cropped image +istream = imgTools.encodeCroppedImage(container, "image/jpeg", 0, 0, 16, 16); +encodedBytes = streamToArray(istream); + +// Get bytes for exected result +refName = "image2jpg16x16cropped.jpg"; +refFile = do_get_file(refName); +istream = getFileInputStream(refFile); +do_check_eq(istream.available(), 879); +referenceBytes = streamToArray(istream); + +// compare the encoder's output to the reference file. +compareArrays(encodedBytes, referenceBytes); + + +/* ========== 16 ========== */ +testnum++; +testdesc = "test cropping a JPG with an offset"; + +// we'll reuse the container from the previous test +istream = imgTools.encodeCroppedImage(container, "image/jpeg", 16, 16, 16, 16); +encodedBytes = streamToArray(istream); + +// Get bytes for exected result +refName = "image2jpg16x16cropped2.jpg"; +refFile = do_get_file(refName); +istream = getFileInputStream(refFile); +do_check_eq(istream.available(), 878); +referenceBytes = streamToArray(istream); + +// compare the encoder's output to the reference file. +compareArrays(encodedBytes, referenceBytes); + + +/* ========== 17 ========== */ +testnum++; +testdesc = "test cropping a JPG without a given height"; + +// we'll reuse the container from the previous test +istream = imgTools.encodeCroppedImage(container, "image/jpeg", 0, 0, 16, 0); +encodedBytes = streamToArray(istream); + +// Get bytes for exected result +refName = "image2jpg16x32cropped3.jpg"; +refFile = do_get_file(refName); +istream = getFileInputStream(refFile); +do_check_eq(istream.available(), 1127); +referenceBytes = streamToArray(istream); + +// compare the encoder's output to the reference file. +compareArrays(encodedBytes, referenceBytes); + + +/* ========== 18 ========== */ +testnum++; +testdesc = "test cropping a JPG without a given width"; + +// we'll reuse the container from the previous test +istream = imgTools.encodeCroppedImage(container, "image/jpeg", 0, 0, 0, 16); +encodedBytes = streamToArray(istream); + +// Get bytes for exected result +refName = "image2jpg32x16cropped4.jpg"; +refFile = do_get_file(refName); +istream = getFileInputStream(refFile); +do_check_eq(istream.available(), 1135); +referenceBytes = streamToArray(istream); + +// compare the encoder's output to the reference file. +compareArrays(encodedBytes, referenceBytes); + + +/* ========== 19 ========== */ +testnum++; +testdesc = "test cropping a JPG without a given width and height"; + +// we'll reuse the container from the previous test +istream = imgTools.encodeCroppedImage(container, "image/jpeg", 0, 0, 0, 0); +encodedBytes = streamToArray(istream); + +// Get bytes for exected result +refName = "image2jpg32x32.jpg"; +refFile = do_get_file(refName); +istream = getFileInputStream(refFile); +do_check_eq(istream.available(), 1634); +referenceBytes = streamToArray(istream); + +// compare the encoder's output to the reference file. +compareArrays(encodedBytes, referenceBytes); + + +/* ========== 20 ========== */ +testnum++; +testdesc = "test scaling a JPG without a given width"; + +// we'll reuse the container from the previous test +istream = imgTools.encodeScaledImage(container, "image/jpeg", 0, 16); +encodedBytes = streamToArray(istream); + +// Get bytes for exected result +refName = "image2jpg32x16scaled.jpg"; +refFile = do_get_file(refName); +istream = getFileInputStream(refFile); +do_check_eq(istream.available(), 1227); +referenceBytes = streamToArray(istream); + +// compare the encoder's output to the reference file. +compareArrays(encodedBytes, referenceBytes); + + +/* ========== 21 ========== */ +testnum++; +testdesc = "test scaling a JPG without a given height"; + +// we'll reuse the container from the previous test +istream = imgTools.encodeScaledImage(container, "image/jpeg", 16, 0); +encodedBytes = streamToArray(istream); + +// Get bytes for exected result +refName = "image2jpg16x32scaled.jpg"; +refFile = do_get_file(refName); +istream = getFileInputStream(refFile); +do_check_eq(istream.available(), 1219); +referenceBytes = streamToArray(istream); + +// compare the encoder's output to the reference file. +compareArrays(encodedBytes, referenceBytes); + + +/* ========== 22 ========== */ +testnum++; +testdesc = "test scaling a JPG without a given width and height"; + +// we'll reuse the container from the previous test +istream = imgTools.encodeScaledImage(container, "image/jpeg", 0, 0); +encodedBytes = streamToArray(istream); + +// Get bytes for exected result +refName = "image2jpg32x32.jpg"; +refFile = do_get_file(refName); +istream = getFileInputStream(refFile); +do_check_eq(istream.available(), 1634); +referenceBytes = streamToArray(istream); + +// compare the encoder's output to the reference file. +compareArrays(encodedBytes, referenceBytes); + + +/* ========== 22 ========== */ +testnum++; +testdesc = "test invalid arguments for cropping"; + +var numErrors = 0; + +try { + // width/height can't be negative + imgTools.encodeScaledImage(container, "image/jpeg", -1, -1); +} catch (e) { numErrors++; } + +try { + // offsets can't be negative + imgTools.encodeCroppedImage(container, "image/jpeg", -1, -1, 16, 16); +} catch (e) { numErrors++; } + +try { + // width/height can't be negative + imgTools.encodeCroppedImage(container, "image/jpeg", 0, 0, -1, -1); +} catch (e) { numErrors++; } + +try { + // out of bounds + imgTools.encodeCroppedImage(container, "image/jpeg", 17, 17, 16, 16); +} catch (e) { numErrors++; } + +try { + // out of bounds + imgTools.encodeCroppedImage(container, "image/jpeg", 0, 0, 33, 33); +} catch (e) { numErrors++; } + +try { + // out of bounds + imgTools.encodeCroppedImage(container, "image/jpeg", 1, 1, 0, 0); +} catch (e) { numErrors++; } + +do_check_eq(numErrors, 6); + + +/* ========== bug 363986 ========== */ +testnum = 363986; +testdesc = "test PNG and JPEG encoders' Read/ReadSegments methods"; + +var testData = + [{preImage: "image3.ico", + preImageMimeType: "image/x-icon", + refImage: "image3ico16x16.png", + refImageMimeType: "image/png"}, + {preImage: "image1.png", + preImageMimeType: "image/png", + refImage: "image1png64x64.jpg", + refImageMimeType: "image/jpeg"}]; + +for(var i=0; i<testData.length; ++i) { + var dict = testData[i]; + + var imgFile = do_get_file(dict["refImage"]); + var istream = getFileInputStream(imgFile); + var refBytes = streamToArray(istream); + + imgFile = do_get_file(dict["preImage"]); + istream = getFileInputStream(imgFile); + + var container = imgTools.decodeImage(istream, dict["preImageMimeType"]); + + istream = imgTools.encodeImage(container, dict["refImageMimeType"]); + + var sstream = Cc["@mozilla.org/storagestream;1"]. + createInstance(Ci.nsIStorageStream); + sstream.init(4096, 4294967295, null); + var ostream = sstream.getOutputStream(0); + var bostream = Cc["@mozilla.org/network/buffered-output-stream;1"]. + createInstance(Ci.nsIBufferedOutputStream); + + //use a tiny buffer to make sure the image data doesn't fully fit in it + bostream.init(ostream, 8); + + bostream.writeFrom(istream, istream.available()); + bostream.flush(); bostream.close(); + + var encBytes = streamToArray(sstream.newInputStream(0)); + + compareArrays(refBytes, encBytes); +} + + +/* ========== bug 413512 ========== */ +testnum = 413512; +testdesc = "test decoding bad favicon (bug 413512)"; + +imgName = "bug413512.ico"; +inMimeType = "image/x-icon"; +imgFile = do_get_file(imgName); + +istream = getFileInputStream(imgFile); +do_check_eq(istream.available(), 17759); +var errsrc = "none"; + +try { + container = imgTools.decodeImage(istream, inMimeType); + + // We expect to hit an error during encoding because the ICO header of the + // image is fine, but the actual resources are corrupt. Since decodeImage() + // only performs a metadata decode, it doesn't decode far enough to realize + // this, but we'll find out when we do a full decode during encodeImage(). + try { + istream = imgTools.encodeImage(container, "image/png"); + } catch (e) { + err = e; + errsrc = "encode"; + } +} catch (e) { + err = e; + errsrc = "decode"; +} + +do_check_eq(errsrc, "encode"); +checkExpectedError(/NS_ERROR_FAILURE/, err); + + +/* ========== bug 815359 ========== */ +testnum = 815359; +testdesc = "test correct ico hotspots (bug 815359)"; + +imgName = "bug815359.ico"; +inMimeType = "image/x-icon"; +imgFile = do_get_file(imgName); + +istream = getFileInputStream(imgFile); +do_check_eq(istream.available(), 4286); + +container = imgTools.decodeImage(istream, inMimeType); + +var props = container.QueryInterface(Ci.nsIProperties); + +do_check_eq(props.get("hotspotX", Ci.nsISupportsPRUint32).data, 10); +do_check_eq(props.get("hotspotY", Ci.nsISupportsPRUint32).data, 9); + + +/* ========== end ========== */ + +} catch (e) { + throw "FAILED in test #" + testnum + " -- " + testdesc + ": " + e; +} +}; |