# -*- coding: utf-8 -*- # *************************************************************************** # * Copyright (c) 2021 Chris Hennes * # * * # * This program is free software; you can redistribute it and/or modify * # * it under the terms of the GNU Lesser General Public License (LGPL) * # * as published by the Free Software Foundation; either version 2 of * # * the License, or (at your option) any later version. * # * for detail see the LICENCE text file. * # * * # * This program is distributed in the hope that it will be useful, * # * but WITHOUT ANY WARRANTY; without even the implied warranty of * # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * # * GNU Library General Public License for more details. * # * * # * You should have received a copy of the GNU Library General Public * # * License along with this program; if not, write to the Free Software * # * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * # * USA * # * * # *************************************************************************** import unittest import FreeCAD import Start from StartPage import StartPage import re class TestStartPage(unittest.TestCase): """Basic validation of the generated Start page.""" MODULE = 'TestStartPage' # file name without extension def setUp(self): pass def test_all_css_placeholders_removed(self): """Check to see if all of the CSS placeholders have been replaced.""" placeholders = ["BACKGROUND","BGTCOLOR","FONTFAMILY","FONTSIZE","LINKCOLOR", "TEXTCOLOR","BOXCOLOR","BASECOLOR","SHADOW"] page = StartPage.handle() for placeholder in placeholders: self.assertNotIn (placeholder, page, "{} was not removed from the CSS".format(placeholder)) def test_all_js_placeholders_removed(self): """Check to see if all of the JavaScript placeholders have been replaced.""" placeholders = ["IMAGE_SRC_INSTALLED"] page = StartPage.handle() for placeholder in placeholders: self.assertNotIn (placeholder, page, "{} was not removed from the JS".format(placeholder)) def test_all_html_placeholders_removed(self): """Check to see if all of the HTML placeholders have been replaced.""" placeholders = ["T_TITLE","VERSIONSTRING","T_DOCUMENTS","T_HELP","T_ACTIVITY", "SECTION_RECENTFILES","T_TIP","T_ADJUSTRECENT","SECTION_EXAMPLES", "SECTION_CUSTOM","T_CUSTOM","T_NOTES","T_GENERALDOCUMENTATION", "IMAGE_SRC_USERHUB", "T_USERHUB", "T_DESCR_USERHUB", "IMAGE_SRC_POWERHUB","T_POWERHUB","T_DESCR_POWERHUB", "IMAGE_SRC_DEVHUB", "T_DEVHUB", "T_DESCR_DEVHUB", "IMAGE_SRC_MANUAL", "T_MANUAL", "T_DESCR_MANUAL", "T_WBHELP","T_DESCR_WBHELP","UL_WORKBENCHES", "T_COMMUNITYHELP","T_DESCR_COMMUNITYHELP1","T_DESCR_COMMUNITYHELP2", "T_DESCR_COMMUNITYHELP3","T_ADDONS","T_DESCR_ADDONS", "T_OFFLINEPLACEHOLDER","T_OFFLINEHELP","T_EXTERNALLINKS", "T_RECENTCOMMITS","T_DESCR_RECENTCOMMITS","T_EXTERNALLINKS", "T_SEEONGITHUB","T_FORUM","T_DESCR_FORUM"] page = StartPage.handle() for placeholder in placeholders: self.assertNotIn (placeholder, page, "{} was not removed from the HTML".format(placeholder)) def test_files_do_not_contain_backslashes(self): # This would be caught by the W3C validator if we didn't sanitize the filenames before sending them. page = StartPage.handle() fileRE = re.compile(r'"file:///(.*?)"') results = fileRE.findall(string=page) badFilenames = [] for result in results: if result.find("\\") != -1: badFilenames.append(result) if len(badFilenames) > 0: self.fail("The following filenames contain backslashes, which is prohibited in HTML: {}".format(badFilenames)) def test_html_validates(self): # Send the generated html to the W3C validator for analysis (removing potentially-sensitive data first) import urllib.request import os import json page = self.sanitize(StartPage.handle()) # Remove potentially sensitive data # For debugging, if you want to ensure that the sanitization worked correctly: # from pathlib import Path # home = str(Path.home()) # f=open(home+"/test.html", "w") # f.write(page) # f.close() validation_url = "https://validator.w3.org/nu/?out=json" data = page.encode('utf-8') # data should be bytes req = urllib.request.Request(validation_url, data) req.add_header("Content-type","text/html; charset=utf-8") errorCount = 0 warningCount = 0 infoCount = 0 validationResultString = "" try: with urllib.request.urlopen (req) as response: text = response.read() responseJSON = json.loads(text) for message in responseJSON["messages"]: if "type" in message: if message["type"] == "info": if "subtype" in message: if message["subtype"] == "warning": warningCount += 1 validationResultString += "WARNING: {}\n".format(ascii(message["message"])) else: infoCount += 1 validationResultString += "INFO: {}\n".format(ascii(message["message"])) elif message["type"] == "error": errorCount += 1 validationResultString += "ERROR: {}\n".format(ascii(message["message"])) elif message["type"] == "non-document-error": FreeCAD.Console.PrintWarning("W3C validator returned a non-document error:\n {}".format(message)) return except urllib.error.HTTPError as e: FreeCAD.Console.PrintWarning("W3C validator returned response code {}".format(e.code)) except urllib.error.URLError: FreeCAD.Console.PrintWarning("Could not communicate with W3C validator") if errorCount > 0 or warningCount > 0: StartPage.exportTestFile() FreeCAD.Console.PrintWarning("HTML validation failed: Start page source written to your home directory for analysis.") self.fail("W3C Validator analysis shows the Start page has {} errors and {} warnings:\n\n{}".format(errorCount, warningCount, validationResultString)) elif infoCount > 0: FreeCAD.Console.PrintWarning("The Start page is valid HTML, but the W3C sent back {} informative messages:\n{}.".format(infoCount,validationResultString)) def sanitize (self, html): # Anonymize all local filenames fileRE = re.compile(r'"file:///.*?"') html = fileRE.sub(repl=r'"file:///A/B/C"', string=html) # Anonymize titles, which are used for mouseover text and might contain document information titleRE = re.compile(r'title="[\s\S]*?"') # Some titles have newlines in them html = titleRE.sub(repl=r'title="Y"', string=html) # Anonymize the document names, which we display in

tags h4RE = re.compile(r'

.*?

') html = h4RE.sub(repl=r'

Z

', string=html) # Remove any simple single-line paragraphs, which might contain document author information, file size information, etc. pRE = re.compile(r'

[^<]*?

') html = pRE.sub(repl=r'

X

', string=html) return html