Forráskód Böngészése

ensuring internal variables of common module are not changed by providing getter functions, splitting out I18n tests

El RIDO 8 éve
szülő
commit
3fed63ce28
3 módosított fájl, 174 hozzáadás és 42 törlés
  1. 62 34
      js/common.js
  2. 8 8
      js/test/Helper.js
  3. 104 0
      js/test/I18n.js

+ 62 - 34
js/common.js

@@ -1,43 +1,12 @@
 'use strict';
 
-exports.a2zString = ['a','b','c','d','e','f','g','h','i','j','k','l','m',
-                     'n','o','p','q','r','s','t','u','v','w','x','y','z'];
-exports.alnumString = exports.a2zString.concat(['0','1','2','3','4','5','6','7','8','9']);
-exports.queryString = exports.alnumString.concat(['+','%','&','.','*','-','_']);
-exports.base64String = exports.alnumString.concat(['+','/','=']).concat(
-    exports.a2zString.map(function(c) {
-        return c.toUpperCase();
-    })
-);
-// schemas supported by the whatwg-url library
-exports.schemas = ['ftp','gopher','http','https','ws','wss'];
-exports.supportedLanguages = ['de', 'es', 'fr', 'it', 'no', 'pl', 'pt', 'oc', 'ru', 'sl', 'zh'];
-exports.mimeTypes = ['image/png', 'application/octet-stream'];
-
+// testing prerequisites
 global.jsc = require('jsverify');
 global.jsdom = require('jsdom-global');
 global.cleanup = global.jsdom();
 global.fs = require('fs');
 
-/**
- * character to HTML entity lookup table
- *
- * @see    {@link https://github.com/janl/mustache.js/blob/master/mustache.js#L60}
- */
-var entityMap = {
-        '&': '&',
-        '<': '&lt;',
-        '>': '&gt;',
-        '"': '&quot;',
-        "'": '&#39;',
-        '/': '&#x2F;',
-        '`': '&#x60;',
-        '=': '&#x3D;'
-    },
-    logFile = fs.createWriteStream('test.log'),
-    mimeFile = fs.createReadStream('/etc/mime.types'),
-    mimeLine = '';
-
+// application libraries to test
 global.$ = global.jQuery = require('./jquery-3.1.1');
 global.sjcl = require('./sjcl-1.0.6');
 global.Base64 = require('./base64-2.1.9').Base64;
@@ -51,6 +20,38 @@ global.DOMPurify = require('./purify.min');
 require('./bootstrap-3.3.7');
 require('./privatebin');
 
+// internal variables
+var a2zString = ['a','b','c','d','e','f','g','h','i','j','k','l','m',
+                     'n','o','p','q','r','s','t','u','v','w','x','y','z'],
+    alnumString = a2zString.concat(['0','1','2','3','4','5','6','7','8','9']),
+    queryString = alnumString.concat(['+','%','&','.','*','-','_']),
+    base64String = alnumString.concat(['+','/','=']).concat(
+        a2zString.map(function(c) {
+            return c.toUpperCase();
+        })
+    ),
+    schemas = ['ftp','gopher','http','https','ws','wss'],
+    supportedLanguages = ['de', 'es', 'fr', 'it', 'no', 'pl', 'pt', 'oc', 'ru', 'sl', 'zh'],
+    mimeTypes = ['image/png', 'application/octet-stream'],
+    /**
+     * character to HTML entity lookup table
+     *
+     * @see    {@link https://github.com/janl/mustache.js/blob/master/mustache.js#L60}
+     */
+    entityMap = {
+        '&': '&amp;',
+        '<': '&lt;',
+        '>': '&gt;',
+        '"': '&quot;',
+        "'": '&#39;',
+        '/': '&#x2F;',
+        '`': '&#x60;',
+        '=': '&#x3D;'
+    },
+    logFile = fs.createWriteStream('test.log'),
+    mimeFile = fs.createReadStream('/etc/mime.types'),
+    mimeLine = '';
+
 // redirect console messages to log file
 console.info = console.warn = console.error = function () {
     logFile.write(Array.prototype.slice.call(arguments).join('') + '\n');
@@ -87,10 +88,12 @@ function parseMime(line) {
         line = line.substring(0, index);
     }
     if (line.length > 0) {
-        exports.mimeTypes.push(line);
+        mimeTypes.push(line);
     }
 }
 
+// common testing helper functions
+
 /**
  * convert all applicable characters to HTML entities
  *
@@ -107,3 +110,28 @@ exports.htmlEntities = function(str) {
         });
 }
 
+// provides random lowercase characters from a to z
+exports.jscA2zString = function() {
+    return jsc.elements(a2zString);
+}
+
+// provides random lowercase alpha numeric characters (a to z and 0 to 9)
+exports.jscAlnumString = function() {
+    return jsc.elements(alnumString);
+}
+
+// provides random characters allowed in GET queries
+exports.jscQueryString = function() {
+    return jsc.elements(queryString);
+}
+
+// provides a random URL schema supported by the whatwg-url library
+exports.jscSchemas = function() {
+    return jsc.elements(schemas);
+}
+
+// provides a random supported language string
+exports.jscSupportedLanguages = function() {
+    return jsc.elements(supportedLanguages);
+}
+

+ 8 - 8
js/test/Helper.js

@@ -53,7 +53,7 @@ describe('Helper', function () {
         this.timeout(30000);
         jsc.property(
             'selection contains content of given ID',
-            jsc.nearray(jsc.nearray(jsc.elements(common.alnumString))),
+            jsc.nearray(jsc.nearray(common.jscAlnumString())),
             'nearray string',
             function (ids, contents) {
                 var html = '',
@@ -90,9 +90,9 @@ describe('Helper', function () {
             'replaces URLs with anchors',
             'string',
             jsc.elements(['http', 'https', 'ftp']),
-            jsc.nearray(jsc.elements(common.a2zString)),
-            jsc.array(jsc.elements(common.queryString)),
-            jsc.array(jsc.elements(common.queryString)),
+            jsc.nearray(common.jscA2zString()),
+            jsc.array(common.jscQueryString()),
+            jsc.array(common.jscQueryString()),
             'string',
             function (prefix, schema, address, query, fragment, postfix) {
                 var query = query.join(''),
@@ -117,7 +117,7 @@ describe('Helper', function () {
         jsc.property(
             'replaces magnet links with anchors',
             'string',
-            jsc.array(jsc.elements(common.queryString)),
+            jsc.array(common.jscQueryString()),
             'string',
             function (prefix, query, postfix) {
                 var url = 'magnet:?' + query.join('').replace(/^&+|&+$/gm,''),
@@ -244,9 +244,9 @@ describe('Helper', function () {
 
         jsc.property(
             'returns the URL without query & fragment',
-            jsc.elements(common.schemas),
-            jsc.nearray(jsc.elements(common.a2zString)),
-            jsc.array(jsc.elements(common.queryString)),
+            common.jscSchemas(),
+            jsc.nearray(common.jscA2zString()),
+            jsc.array(common.jscQueryString()),
             'string',
             function (schema, address, query, fragment) {
                 var expected = schema + '://' + address.join('') + '/',

+ 104 - 0
js/test/I18n.js

@@ -0,0 +1,104 @@
+'use strict';
+var common = require('../common');
+
+describe('I18n', function () {
+    describe('translate', function () {
+        before(function () {
+            $.PrivateBin.I18n.reset();
+        });
+
+        jsc.property(
+            'returns message ID unchanged if no translation found',
+            'string',
+            function (messageId) {
+                messageId   = messageId.replace(/%(s|d)/g, '%%');
+                var plurals = [messageId, messageId + 's'],
+                    fake    = [messageId],
+                    result  = $.PrivateBin.I18n.translate(messageId);
+                $.PrivateBin.I18n.reset();
+
+                var alias = $.PrivateBin.I18n._(messageId);
+                $.PrivateBin.I18n.reset();
+
+                var p_result = $.PrivateBin.I18n.translate(plurals);
+                $.PrivateBin.I18n.reset();
+
+                var p_alias = $.PrivateBin.I18n._(plurals);
+                $.PrivateBin.I18n.reset();
+
+                var f_result = $.PrivateBin.I18n.translate(fake);
+                $.PrivateBin.I18n.reset();
+
+                var f_alias = $.PrivateBin.I18n._(fake);
+                $.PrivateBin.I18n.reset();
+
+                return messageId === result && messageId === alias &&
+                    messageId === p_result && messageId === p_alias &&
+                    messageId === f_result && messageId === f_alias;
+            }
+        );
+        jsc.property(
+            'replaces %s in strings with first given parameter',
+            'string',
+            '(small nearray) string',
+            'string',
+            function (prefix, params, postfix) {
+                prefix    =    prefix.replace(/%(s|d)/g, '%%');
+                params[0] = params[0].replace(/%(s|d)/g, '%%');
+                postfix   =   postfix.replace(/%(s|d)/g, '%%');
+                var translation = prefix + params[0] + postfix;
+                params.unshift(prefix + '%s' + postfix);
+                var result = $.PrivateBin.I18n.translate.apply(this, params);
+                $.PrivateBin.I18n.reset();
+                var alias = $.PrivateBin.I18n._.apply(this, params);
+                $.PrivateBin.I18n.reset();
+                return translation === result && translation === alias;
+            }
+        );
+    });
+
+    describe('getPluralForm', function () {
+        before(function () {
+            $.PrivateBin.I18n.reset();
+        });
+
+        jsc.property(
+            'returns valid key for plural form',
+            common.jscSupportedLanguages(),
+            'integer',
+            function(language, n) {
+                $.PrivateBin.I18n.reset(language);
+                var result = $.PrivateBin.I18n.getPluralForm(n);
+                // arabic seems to have the highest plural count with 6 forms
+                return result >= 0 && result <= 5;
+            }
+        );
+    });
+
+    // loading of JSON via AJAX needs to be tested in the browser, this just mocks it
+    // TODO: This needs to be tested using a browser.
+    describe('loadTranslations', function () {
+        this.timeout(30000);
+        before(function () {
+            $.PrivateBin.I18n.reset();
+        });
+
+        jsc.property(
+            'downloads and handles any supported language',
+            common.jscSupportedLanguages(),
+            function(language) {
+                var clean = jsdom('', {url: 'https://privatebin.net/', cookie: ['lang=' + language]});
+
+                $.PrivateBin.I18n.reset('en');
+                $.PrivateBin.I18n.loadTranslations();
+                $.PrivateBin.I18n.reset(language, require('../../i18n/' + language + '.json'));
+                var result = $.PrivateBin.I18n.translate('en'),
+                    alias  = $.PrivateBin.I18n._('en');
+
+                clean();
+                return language === result && language === alias;
+            }
+        );
+    });
+});
+