This commit is contained in:
thepra 2017-04-02 18:07:06 +02:00
parent f1ed623905
commit f4c8c653a5
19 changed files with 1477 additions and 0 deletions

28
TestWebGen.sln Normal file
View File

@ -0,0 +1,28 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TestWebGen", "TestWebGen\TestWebGen.vcxproj", "{13843C6A-4801-49A1-98AC-A04441D29730}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{13843C6A-4801-49A1-98AC-A04441D29730}.Debug|x64.ActiveCfg = Debug|x64
{13843C6A-4801-49A1-98AC-A04441D29730}.Debug|x64.Build.0 = Debug|x64
{13843C6A-4801-49A1-98AC-A04441D29730}.Debug|x86.ActiveCfg = Debug|Win32
{13843C6A-4801-49A1-98AC-A04441D29730}.Debug|x86.Build.0 = Debug|Win32
{13843C6A-4801-49A1-98AC-A04441D29730}.Release|x64.ActiveCfg = Release|x64
{13843C6A-4801-49A1-98AC-A04441D29730}.Release|x64.Build.0 = Release|x64
{13843C6A-4801-49A1-98AC-A04441D29730}.Release|x86.ActiveCfg = Release|Win32
{13843C6A-4801-49A1-98AC-A04441D29730}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

10
TestWebGen/CTML.h Normal file
View File

@ -0,0 +1,10 @@
/*
CTML - written by Tinfoilboy
uses the MIT License (https://github.com/tinfoilboy/CFML/blob/master/LICENSE)
*/
#pragma once
namespace CTML {
static int INDENT_SPACES = 4;
}
#include "Node.h"
#include "Document.h"

79
TestWebGen/Document.h Normal file
View File

@ -0,0 +1,79 @@
/*
CTML - written by Tinfoilboy
uses the MIT License (https://github.com/tinfoilboy/CFML/blob/master/LICENSE)
*/
#pragma once
#include "Node.h"
#include <string>
#include <fstream>
namespace CTML {
class Document {
// the doctype of this document
Node m_doctype;
// the head tag of this document
Node m_head;
// the body tag of this document
Node m_body;
public:
// the default constructor for a document
Document() {
// create and set the doctype to html
this->m_doctype = Node("", "html");
this->m_doctype.SetType(NodeType::DOCUMENT_TYPE);
// create the head tag
this->m_head = Node("head");
// create the body tag
this->m_body = Node("body");
}
// add a node to the head element
void AddNodeToHead(Node node) {
this->m_head.AppendChild(node);
}
// add a node to the body element
void AddNodeToBody(Node node) {
this->m_body.AppendChild(node);
}
// gets the current document as a string
std::string ToString(const Readability& readability) const {
bool isMultiline = (readability == Readability::MULTILINE || readability == Readability::MULTILINE_BR);
std::string doc = "";
// add the doctype to the string
doc += m_doctype.ToString(readability, 0);
// every document needs an html tag, add it
doc += "<html>";
// if we want readability, append a newline to the html beginning tag
doc += ((isMultiline) ? "\n" : "");
// append the head tag and its children
doc += m_head.ToString(readability, 1) + ((isMultiline) ? "\n" : "");
// append the body tag and its children
doc += m_body.ToString(readability, 1) + ((isMultiline) ? "\n" : "");
// close the html tag
doc += "</html>";
return doc;
}
// get the current document as a tree represented in a string
std::string ToTree() const {
std::string treeStr = "";
treeStr += "html\n";
treeStr += m_head.GetTreeString(0);
treeStr += m_body.GetTreeString(0);
return treeStr;
}
// write the current document to a file
bool WriteToFile(const std::string& filePath, const Readability& readability) const {
std::ofstream file(filePath.c_str());
if (file.is_open()) {
file << this->ToString(readability);
file.close();
return true;
}
return false;
}
};
}

View File

@ -0,0 +1,8 @@
#pragma once
class EnvironmentScanGrabTool
{
public:
EnvironmentScanGrabTool();
~EnvironmentScanGrabTool();
};

View File

@ -0,0 +1,12 @@
#include "stdafx.h"
#include "EnvironmentScanGrabTool.h"
EnvironmentScanGrabTool::EnvironmentScanGrabTool()
{
}
EnvironmentScanGrabTool::~EnvironmentScanGrabTool()
{
}

View File

@ -0,0 +1,185 @@
#pragma once
#include "stdafx.h"
#include "GeneralBuilder.h"
#include "ThePraDev.h"
GeneralBuilder::GeneralBuilder()
{
}
GeneralBuilder::~GeneralBuilder()
{
}
list<Document> GeneralBuilder::BuildThePraSite(Sites site)
{
Utilities tool{Utilities()};
string cPath{tool.GetCurrentPath()};
switch (site)
{
case DEV:
{
ThePraDev a{ThePraDev()};
string link = "https://www.thepra-dev.com/", html = ".html";
Document index = Document();
Head(index, link + "index" + html, "ThePra WebSite");
Body(index, cPath + a.contentLinks[0], site);
Document code = Document();
Head(code, link + "code" + html, "ThePra Code");
Body(code, cPath + a.contentLinks[1], site);
Document blog = Document();
Head(blog, link + "blog" + html, "ThePra Blog");
Body(blog, cPath + a.contentLinks[2], site);
Document about = Document();
Head(about, link + "about" + html, "ThePra About");
Body(about, cPath + a.contentLinks[3], site);
Document contact = Document();
Head(contact, link + "contact" + html, "ThePra Contact");
Body(contact, cPath + a.contentLinks[4], site);
return{index,code,blog,about,contact};
}
break;
case ART:
{
string link = "http://art.thepra-dev.com/", html = ".html";
Document index = Document();
Head(index, link + "index" + html, "title");
Body(index, cPath, site);
Document aboutme = Document();
Head(aboutme, link + "aboutme" + html, "title");
Body(aboutme, cPath, site);
Document twitch = Document();
Head(twitch, link + "twitch" + html, "title");
Body(twitch, cPath, site);
Document twitter = Document();
Head(twitter, link + "twitter" + html, "title");
Body(twitter, cPath, site);
Document youtubePosts = Document();
Head(youtubePosts, link + "youtubePosts" + html, "title");
Body(youtubePosts, cPath, site);
return{index,aboutme,twitch,twitter,youtubePosts};
}
break;
default:
break;
}
return list<Document>();
}
void GeneralBuilder::Head(Document &file,
string canonicalURL,
string title,
Levels level,
string description,
list<string> cssStyles)
{
string whichLevel = ChooseLevel(level);
// ESSENTIAL
Node charset = Node(meta).SetAttribute("charset", "utf-8").UseClosingTag(false);
Node edge = Node(meta).SetAttribute(http_equiv, "x-ua-compatible").SetAttribute(content, "ie=edge").UseClosingTag(false);
Node viewport = Node(meta).SetAttribute(name, "viewport").SetAttribute(content, "width=device-width, initial-scale=1").UseClosingTag(false);
Node titleP = Node("title", title);
// OTHER
Node canon = Node(link).SetAttribute(rel, "canonical").SetAttribute(href, canonicalURL).UseClosingTag(false);
Node base = Node("base").SetAttribute(href, canonicalURL).UseClosingTag(false);
Node contentSecurityPolicy = Node(meta).SetAttribute(http_equiv, "Content-Security-Policy").SetAttribute(content, "default-src 'self'").UseClosingTag(false);
Node descriptionP = Node(meta).SetAttribute(name, "description").SetAttribute(content, description).UseClosingTag(false);
Node robots = Node(meta).SetAttribute(name, "robots").SetAttribute(content, "index,follow,noodp").UseClosingTag(false);
Node googleBot = Node(meta).SetAttribute(name, "googlebot").SetAttribute(content, "index,follow").UseClosingTag(false);
Node referrer = Node(meta).SetAttribute(name, "referrer").SetAttribute(content, "no-referrer").UseClosingTag(false);
Node icon = Node(link).SetAttribute(rel, "icon").SetAttribute(href, whichLevel + "icon/favicon.png").SetAttribute("type", "image/png").UseClosingTag(false);
file.AddNodeToHead(charset);
file.AddNodeToHead(edge);
file.AddNodeToHead(viewport);
file.AddNodeToHead(titleP);
file.AddNodeToHead(base);
file.AddNodeToHead(canon);
if (cssStyles.front() == "")
{
Node style = Node(link).SetAttribute(rel, "stylesheet").SetAttribute(href, whichLevel + "style.css").UseClosingTag(false);
file.AddNodeToHead(style);
}
else
{
for each (string s in cssStyles)
{
Node style = Node(link).SetAttribute(rel, "stylesheet").SetAttribute(href, whichLevel + s).UseClosingTag(false);
file.AddNodeToHead(style);
}
}
file.AddNodeToHead(contentSecurityPolicy);
file.AddNodeToHead(descriptionP);
file.AddNodeToHead(robots);
file.AddNodeToHead(googleBot);
file.AddNodeToHead(referrer);
file.AddNodeToHead(icon);
}
void GeneralBuilder::Body(Document &file, string cPath, Sites site, PageType type)
{
switch (site)
{
case DEV:
{
ThePraDev::BuildBody(file, cPath, ROOT, type);
}
case ART:
{
}
default:// I'm drunk
break;
}
}
void GeneralBuilder::BuildHTMLFiles(Sites site, list<Document> rootFiles, list<Document> postFiles)
{
string cDevOutputPath{Utilities::GetCurrentPath() + "\\output_thepradev\\"};
string postcDevOutputPath{cDevOutputPath + "postsContent\\"};
path dir = current_path();
cout << dir.string() << endl;
for (auto& p : directory_iterator(dir))
{
path asd = p.path();
if (!is_directory(p))
cout << p.path().filename().string() << endl;
}
switch (site)
{
case Utilities::DEV:
{
dir.append("thepradev");
path contentDir{dir.append("content")};
path postsContentDir{dir.append("postsContent")};
}
break;
case Utilities::ART:
{
dir.append("thepraart\\");
}
break;
default:
break;
}
}

View File

@ -0,0 +1,28 @@
#pragma once
#include "CTML.h"
#include <list>
#include <string>
#include "Utilities.h"
#include <filesystem>
using namespace CTML;
using namespace std;
class GeneralBuilder : Utilities
{
public:
GeneralBuilder();
~GeneralBuilder();
list<Document> BuildThePraSite(Sites site);
void Head(Document &file,
string canonicalURL,
string title,
Levels level = ROOT,
string description = "",
list<string> cssStyles = {""});
void Body(Document &file,
string cPath,
Sites site,
PageType type = NORMAL);
void BuildHTMLFiles(Sites site, list<Document> rootFiles, list<Document> postFiles = {{}});
};

359
TestWebGen/Node.h Normal file
View File

@ -0,0 +1,359 @@
/*
CTML - written by Tinfoilboy
uses the MIT License (https://github.com/tinfoilboy/CFML/blob/master/LICENSE)
*/
#pragma once
#include <vector>
#include <unordered_map>
#include <string>
#include <sstream>
#include <algorithm>
namespace CTML {
// the types of nodes used for the html
// DOCUMENT_TYPE doesn't use the element name, but uses
// the content to determine the document type to use
// ELEMENT is just a normal element
enum class NodeType { DOCUMENT_TYPE, ELEMENT };
// a few enums for readability of the HTML
// SINGLE_LINE returns the string as one line
// MULTILINE returns the string as multiple lines, which is good for file outputs or readability.
// MULTILINE_BR is essentially the same as MULTILINE, but the difference is that newlines in the content of the node are formatted to use <br> tags.
enum class Readability { SINGLE_LINE, MULTILINE, MULTILINE_BR };
// the state of the Node name parser
// NONE means that nothing is being parsed
// CLASS means that a class attribute is being parsed
// ID means that an ID is being parsed for the node
enum class NodeParser { NONE, CLASS, ID };
class Node {
// the type of node this
NodeType m_type;
// the name of this node, e.g. div, a, span, e.t.c.
std::string m_name;
// the classes for this node
std::string m_classes;
// the ids for this node
std::string m_id;
// the content of this node
std::string m_content;
// determines whether or not to add a closing tag (ie. </name>)
// if this is false, it also doesn't add content to the tag
// as there is nowhere to place content
bool m_closeTag = true;
// the child elements of this node
std::vector<Node> m_children;
// an unordered_map of attributes, name is the attribute name and the value is the attribute value
std::unordered_map<std::string, std::string> m_attributes;
public:
// default constructor, does nothing
Node() = default;
// create a node with the name specified
Node(const std::string& name) {
this->m_type = NodeType::ELEMENT;
this->SetName(name);
}
// create a node with the name specified, also containing the following content
Node(const std::string& name, const std::string& content) {
this->m_type = NodeType::ELEMENT;
this->SetName(name);
this->m_content = content;
}
// return this node as an html string
std::string ToString(Readability readability, int indentLevel) const {
// the element string that will be returned
std::string elem = "";
// the four space indent.
std::string indent = "";
std::string indentContent = "";
// if the readabilty points is either multiline types, this would be true
bool isMultiline = (readability == Readability::MULTILINE || readability == Readability::MULTILINE_BR);
// increment the indent string by four spaces based on the indentLevel
// but only if the readabilty is MULTILINE OR MULTILINE_BR
if (isMultiline) {
for (int i = 0; i < indentLevel; i++) {
indent = std::string(INDENT_SPACES * indentLevel, ' ');
}
// set the m_content indent level to the indent level plus four more spaces
indentContent = std::string(INDENT_SPACES * (indentLevel + 1), ' ');
}
if (this->m_type == NodeType::ELEMENT) {
// construct the first part of the element string, the tag beginning
elem = ((isMultiline) ? indent : "") + "<" + m_name + "";
// add the class list if it isn't empty
if (!m_classes.empty()) {
std::string classTag = "class=\"";
elem += " " + classTag + m_classes + "\"";
}
// add the id list if it isn't empty
if (!m_id.empty()) {
std::string idTag = "id=\"";
elem += " " + idTag + m_id + "\"";
}
// make an iterator for each attribute
for (const auto& attr : m_attributes) {
elem += " " + attr.first + "=\"" + attr.second + "\"";
}
// close the beginning tag
elem += ">";
// only add the content, as well as the closing tag if it is
// specified to do so
if (m_closeTag)
{
// if multiline is specified and the content/children aren't empty, add a newline
if (isMultiline && (!m_content.empty() || !m_children.empty()))
elem += "\n";
// if we have m_content to append
if (!m_content.empty()) {
// format the elements content based on the readability, as well as the indent level for content
elem += _GetFormattedContent(readability, indentContent);
}
// get every child node from the m_children list
for (std::size_t i = 0; i < m_children.size(); ++i) {
const auto& childNode = m_children[i];
// append the child node to the elem string.
// if this is not the last child node append a newline if multiline
elem += childNode.ToString(readability, indentLevel + 1) + ((i != m_children.size() - 1 && isMultiline) ? "\n" : "");
}
// if multiline is specified and the content/children aren't empty, add a newline and indent
elem += ((isMultiline && (!m_content.empty() || !m_children.empty())) ? "\n" + indent : "") + "</" + m_name + ">";
}
}
else if (this->m_type == NodeType::DOCUMENT_TYPE) {
// just construct the docm_type from the m_content given, if readability is wanted, add a newline
elem += "<!DOCTYPE " + m_content + ">" + ((isMultiline) ? "\n" : "");
}
return elem;
}
std::string GetTreeString(int indentLevel) const {
// the tree string
std::string tree;
// indent level
std::string indent(INDENT_SPACES * indentLevel, ' ');
// turn the class list into actual classes for the elements
std::string classList = m_classes;
std::replace(classList.begin(), classList.end(), ' ', '.');
// if the class list isn't empty, prepend a period
if (!classList.empty())
classList = '.' + classList;
// add the current element to the tree
tree += indent + " |_ " + this->m_name + classList + '\n';
// for each child
for (const auto& child : m_children) {
tree += child.GetTreeString(indentLevel + 1) + '\n';
}
return tree;
}
Node& SetName(const std::string& name) {
// the index of a period
const auto periodIndex = name.find('.');
// the index of a pound sign
const auto poundIndex = name.find('#');
// if there are classes in the name
if (periodIndex != std::string::npos || poundIndex != std::string::npos) {
// if the pound index comes before the period index
bool poundBefore = (poundIndex != std::string::npos && poundIndex < periodIndex);
// get the first index for parsing
// if pound comes first, or there are no periods, use the first pound index first
// else use the first period index
const auto ind = ((poundBefore || (periodIndex == std::string::npos && poundIndex != std::string::npos)) ? poundIndex : periodIndex);
// get the element name
std::string elemName = name.substr(0, ind);
// parse the current ids and classes
_ParseClassesAndIDS(name.substr(ind));
// set the element name to the built element name
this->m_name = elemName;
}
else {
this->m_name = name;
}
return *this;
}
std::string GetAttribute(const std::string& name) const {
// the class attribute is tracked with m_classes, so we return that instead of m_attributes[name]
if (name != "class" && name != "id" && m_attributes.count(name) > 0)
return m_attributes.at(name);
else if (name == "class")
return m_classes;
else if (name == "id")
return m_id;
else
return "";
}
std::string GetSelector() const {
std::string classesPeriod = _ReplaceAllOccurrences(m_classes, " ", ".");
return m_name + classesPeriod + "#" + m_id;
}
Node& SetAttribute(std::string name, std::string value) {
// setting the "class" attribute would make there be two class attributes on the element
// so therefore, if the name of this is class, we just override "m_classes"
if (name != "class" && name != "id")
m_attributes[name] = value;
else if (name == "class")
m_classes = value;
else if (name == "id")
m_id = value;
return *this;
}
Node& SetType(NodeType type) {
this->m_type = type;
return *this;
}
Node& SetContent(const std::string& text) {
this->m_content = text;
return *this;
}
Node& ToggleClass(const std::string& className) {
size_t findIndex = m_classes.find(className);
if (findIndex == std::string::npos) {
// append the class
m_classes += ((!m_classes.empty()) ? " " : "") + className;
}
else {
// remove the class
m_classes.erase(findIndex, className.size());
}
return *this;
}
Node& AppendChild(Node child) {
m_children.push_back(child);
return *this;
}
Node& UseClosingTag(bool close) {
this->m_closeTag = close;
return *this;
}
private:
std::string _GetFormattedContent(Readability readability, const std::string& indent) const {
std::string result;
std::istringstream iss(m_content);
// if we are using either variant of multiple lines, run this.
if (readability == Readability::MULTILINE || readability == Readability::MULTILINE_BR) {
// the newline string, differs between MULTILINE and MULTILINE_BR
std::string newline = ((readability == Readability::MULTILINE_BR) ? "\n" + indent + "<br>\n" : "\n");
// the current line iterated
int curLine = 0;
// iterate through each line in this node
for (std::string line; std::getline(iss, line);)
{
result += ((curLine > 0) ? newline : "") + indent + line;
curLine++;
}
}
else {
// iterate through each line in this node
for (std::string line; std::getline(iss, line);)
{
result += line;
}
}
// replaces all instances of "<" in the content with "&lt;", to escape rogue HTML
//result = _ReplaceAllOccurrences(result, "<", "&lt;");
// replaces all instances of ">" in the content with "&gt;" to escape rogue HTML
//result = _ReplaceAllOccurrences(result, ">", "&gt;");
// return the result of the content
return result;
}
std::string _ReplaceAllOccurrences(std::string replacer, const std::string& replacable, const std::string& replace) const {
// the start of the current replacable string
size_t start = 0;
// try and find each occurrence of replaceable until it can't be found
while ((start = replacer.find(replacable, start)) != std::string::npos) {
// replace the actual string
replacer.replace(start, replacable.length(), replace);
// add to the start so that find can be run again
start += replace.length();
}
// return the replaced string
return replacer;
}
int _CountOccurrences(std::string finder, const std::string& findable) const {
// the occurrences of the string
int occurrences = 0;
// the start of the current replacable string
size_t start = 0;
// try and find each occurrence of replaceable until it can't be found
while ((start = finder.find(findable, start)) != std::string::npos) {
// replace the actual string
occurrences++;
// add to the start so that find can be run again
start += findable.length();
}
// return the replaced string
return occurrences;
}
void _ParseClassesAndIDS(std::string classesAndIDs) {
// what is currently being parsed
// zero for nothing
// one for class
// two for id
NodeParser currentlyParsing = NodeParser::NONE;
// the string for the class or ID
std::string attrString;
// iterate through each character in the string
for (unsigned int i = 0; i < classesAndIDs.size(); i++) {
// the current character being iterated
char curChar = classesAndIDs[i];
if (currentlyParsing == NodeParser::NONE) {
// if the current character is a period, set the current parsing to class
// else if the current character is a pound sign, set the current parsing to id
if (curChar == '.') {
currentlyParsing = NodeParser::CLASS;
}
else if (curChar == '#') {
currentlyParsing = NodeParser::ID;
}
}
else {
// if the current character is a period, set the current parsing to class
// else if the current character is a pound sign, set the current parsing to id
if (curChar == '.' || curChar == '#') {
if (currentlyParsing == NodeParser::CLASS)
m_classes += attrString + " ";
else
// if we hit an id, we just reset the id
// this is because HTML only allows for a single id on each element
m_id = attrString;
attrString.clear();
currentlyParsing = ((curChar == '.') ? NodeParser::CLASS : NodeParser::ID);
}
else {
// add the current character to the class or id string
attrString += curChar;
}
}
// if we are at the last character, and are still parsing something, add it to the respective attr
if (currentlyParsing != NodeParser::NONE && i == classesAndIDs.size() - 1) {
if (currentlyParsing == NodeParser::CLASS)
m_classes += attrString;
else
// if we hit an id, we just reset the id
// this is because HTML only allows for a single id on each element
m_id = attrString;
attrString.clear();
}
}
// if there is an extra space at the end of m_classes, remove it
if (!m_classes.empty()) {
if (isspace(m_classes.at(m_classes.size() - 1)))
m_classes = m_classes.substr(0, m_classes.size() - 1);
}
}
};
}

40
TestWebGen/ReadMe.txt Normal file
View File

@ -0,0 +1,40 @@
========================================================================
CONSOLE APPLICATION : TestWebGen Project Overview
========================================================================
AppWizard has created this TestWebGen application for you.
This file contains a summary of what you will find in each of the files that
make up your TestWebGen application.
TestWebGen.vcxproj
This is the main project file for VC++ projects generated using an Application Wizard.
It contains information about the version of Visual C++ that generated the file, and
information about the platforms, configurations, and project features selected with the
Application Wizard.
TestWebGen.vcxproj.filters
This is the filters file for VC++ projects generated using an Application Wizard.
It contains information about the association between the files in your project
and the filters. This association is used in the IDE to show grouping of files with
similar extensions under a specific node (for e.g. ".cpp" files are associated with the
"Source Files" filter).
TestWebGen.cpp
This is the main application source file.
/////////////////////////////////////////////////////////////////////////////
Other standard files:
StdAfx.h, StdAfx.cpp
These files are used to build a precompiled header (PCH) file
named TestWebGen.pch and a precompiled types file named StdAfx.obj.
/////////////////////////////////////////////////////////////////////////////
Other notes:
AppWizard uses "TODO:" comments to indicate parts of the source code you
should add to or customize.
/////////////////////////////////////////////////////////////////////////////

47
TestWebGen/TestWebGen.cpp Normal file
View File

@ -0,0 +1,47 @@
// TestWebGen.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <iostream>
#include "GeneralBuilder.h"
#include <stdio.h>
#include <experimental\filesystem>
#include "Utilities.h"
#include "ThePraDev.h"
using namespace std::experimental::filesystem::v1;
using namespace std;
using namespace CTML;
int main()
{
ThePraDev n{ThePraDev()};
string cDevOutputPath{Utilities::GetCurrentPath()+ "\\output_thepradev\\"};
string postcDevOutputPath{cDevOutputPath + "postsContent\\"};
path dir = canonical(".");
cout << dir.append("thepradev").append("a")<<endl;
/*for (auto& p : directory_iterator(dir))
{
path asd = p.path();
if (!is_directory(p))
cout << asd.append("thepradev") << endl;
}*/
/*int i = 0;
list<Document> wholeSite = list<Document>();
GeneralBuilder dev;
wholeSite = dev.BuildThePraSite(Utilities::DEV);
for each (Document page in wholeSite)
{
page.WriteToFile(cDevOutputPath + n.pages[i++], Readability::MULTILINE);
}*/
cout << "DONE";
getchar();
return 0;
}

View File

@ -0,0 +1,181 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{13843C6A-4801-49A1-98AC-A04441D29730}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>TestWebGen</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>C:\Program Files\boost\boost_1_63_0;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>C:\Program Files\boost\boost_1_63_0\libs\filesystem;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>Use</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>Use</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<Text Include="ReadMe.txt" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="CTML.h" />
<ClInclude Include="Document.h" />
<ClInclude Include="EnvironmentScanGrabTool.h" />
<ClInclude Include="Node.h" />
<ClInclude Include="stdafx.h" />
<ClInclude Include="Utilities.h" />
<ClInclude Include="targetver.h" />
<ClInclude Include="GeneralBuilder.h" />
<ClInclude Include="ThePraDev.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="EnvironmentScanTool.cpp" />
<ClCompile Include="stdafx.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="TestWebGen.cpp" />
<ClCompile Include="GeneralBuilder.cpp" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="..\packages\dirent.1.13.1\build\native\dirent.targets" Condition="Exists('..\packages\dirent.1.13.1\build\native\dirent.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\dirent.1.13.1\build\native\dirent.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\dirent.1.13.1\build\native\dirent.targets'))" />
</Target>
</Project>

View File

@ -0,0 +1,66 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<Text Include="ReadMe.txt" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="stdafx.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="targetver.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="GeneralBuilder.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ThePraDev.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="EnvironmentScanGrabTool.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="CTML.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Document.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Node.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Utilities.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="stdafx.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="TestWebGen.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="GeneralBuilder.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="EnvironmentScanTool.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
</Project>

195
TestWebGen/ThePraDev.h Normal file
View File

@ -0,0 +1,195 @@
#pragma once
#include "Utilities.h"
#include <iostream>
#include <fstream>
class ThePraDev : Utilities
{
public:
string index = "index.html";
string code = "code.html";
string blog = "blog.html";
string about = "about.html";
string contact = "contact.html";
string Home = "Home";
string Code = "Code";
string Blog = "Blog";
string About = "About";
string Contact = "Contact";
string Menu = "Menu";
string contentFolder = "\\thepradev\\content\\";
string contentLinks[5]{
contentFolder + "index.txt",
contentFolder + "code.txt",
contentFolder + "blog.txt",
contentFolder + "about.txt",
contentFolder + "contact.txt"
};
string pages[5]{
"index.html",
"code.html",
"blog.html",
"about.html",
"contact.html"
};
static void BuildBody(Document &file,string cPath, Levels level, PageType ptype = NORMAL);
private:
static list<Node> NavigationBar(Levels level, DeskOrMob mtype);
static list<Node> SingleMainContent(Levels level,string cPath, DeskOrMob mtype, list<string> content = {""});
static Node Extra(Levels level);
static Node Player(Levels level);
};
inline void ThePraDev::BuildBody(Document &file,string cPath, Levels level, PageType ptype)
{
list<Node> navBar = NavigationBar(level, D);
list<Node> navBarM = NavigationBar(level, M);
list<Node> main = SingleMainContent(level, cPath, D);
list<Node> mainM = SingleMainContent(level, cPath, M);
Node desktop = Node("section#desktop");
Node mobile = Node("section#mobile");
for each (Node item in navBar)
{
desktop.AppendChild(item);
}
for each (Node item in navBarM)
{
mobile.AppendChild(item);
}
for each (Node item in main)
{
desktop.AppendChild(item);
}
for each (Node item in mainM)
{
mobile.AppendChild(item);
}
file.AddNodeToBody(desktop);
file.AddNodeToBody(mobile);
}
inline list<Node> ThePraDev::NavigationBar(Levels level, DeskOrMob mtype)
{
ThePraDev a;
string whichLevel = ChooseLevel(level);
switch (mtype)
{
case D:
{
Node elem0 = Node("div.navigation_bar");
Node elem1 = Node("img").SetAttribute(a.src, whichLevel + "icon/up.png").SetAttribute(a.alt, "Upper Decoration").UseClosingTag(false);
Node elem2 = Node("ul.bortrr.borbrr");
Node elem3 = Node("li.bortrr").AppendChild(Node(a.a, a.Home).SetAttribute(a.href, whichLevel + a.index));
Node elem4 = Node(a.li).AppendChild(Node(a.a, a.Code).SetAttribute(a.href, whichLevel + a.code));
Node elem5 = Node(a.li).AppendChild(Node(a.a, a.Blog).SetAttribute(a.href, whichLevel + a.blog));
Node elem6 = Node(a.li).AppendChild(Node(a.a, a.About).SetAttribute(a.href, whichLevel + a.about));
Node elem7 = Node(a.li).AppendChild(Node(a.a, a.Contact).SetAttribute(a.href, whichLevel + a.contact));
Node elem8 = Extra(level);
Node elem9 = Node("img").SetAttribute(a.src, whichLevel + "icon/down.png").SetAttribute(a.alt, "Down Decoration").UseClosingTag(false);
elem0.AppendChild(elem1)
.AppendChild(elem2
.AppendChild(elem3)
.AppendChild(elem4)
.AppendChild(elem5)
.AppendChild(elem6)
.AppendChild(elem7)
.AppendChild(elem8))
.AppendChild(elem9);
return{{elem0}};
}
break;
case M:
{
Node elem0 = Node("div.navigation_barm");
Node elem1 = Node("img.immagini_laterali").SetAttribute(a.src, whichLevel + "icon/left.png").SetAttribute(a.alt, "Upper Left Decoration").UseClosingTag(false);
Node elem2 = Node("div.navigation_barminner");
Node elem3 = Node("nav._nav");
Node elem4 = Node("laber.toggle").SetAttribute("for", "drop").SetContent(a.Menu);
Node elem5 = Node("input#drop").SetAttribute("type", "checkbox").UseClosingTag(false);
Node elem6 = Node("ul.menu");
Node elem7 = Node(a.li).AppendChild(Node(a.a, a.Home).SetAttribute(a.href, whichLevel + a.index));
Node elem8 = Node(a.li).AppendChild(Node(a.a, a.Code).SetAttribute(a.href, whichLevel + a.code));
Node elem9 = Node(a.li).AppendChild(Node(a.a, a.Blog).SetAttribute(a.href, whichLevel + a.blog));
Node elem10 = Node(a.li).AppendChild(Node(a.a, a.About).SetAttribute(a.href, whichLevel + a.about));
Node elem11 = Node(a.li).AppendChild(Node(a.a, a.Contact).SetAttribute(a.href, whichLevel + a.contact));
Node elem12 = Node("img.immagini_laterali").SetAttribute(a.src, whichLevel + "icon/right.png").SetAttribute(a.alt, "Upper Right Decoration").UseClosingTag(false);
elem0.AppendChild(elem1)
.AppendChild(elem2
.AppendChild(elem3
.AppendChild(elem4)
.AppendChild(elem5)
.AppendChild(elem6
.AppendChild(elem7)
.AppendChild(elem8)
.AppendChild(elem9)
.AppendChild(elem10)
.AppendChild(elem11))))
.AppendChild(elem12);
return{{elem0}};
}
break;
default: return{{}};
break;
}
}
inline list<Node> ThePraDev::SingleMainContent(Levels level,string cPath, DeskOrMob mtype, list<string> content)
{
ThePraDev a;
string whichLevel = ChooseLevel(level);
Node mainC = Node("div#main");
Node mainMC = mainC;
string STRING;
string contentDesktop = "";
string contentMobile = "";
FullFillContent(cPath, &contentDesktop, &contentMobile);
mainC.SetContent(contentDesktop);
mainMC.SetContent(contentMobile);
/*for each (string item in contentTest)
{
mainC.SetContent(item+"\n");
}*/
if (mtype == D)
return{mainC};
else return{mainMC};
}
inline Node ThePraDev::Extra(Levels level)
{
ThePraDev a;
string whichLevel = ChooseLevel(level);
Node extra = Node("li.borbrr")
.AppendChild(Node(a.a, "+ Extra +"))
.AppendChild(Node("ul.borbrr")
.AppendChild(Node("li.colbk")
.AppendChild(Node("img.fiximgmenu").SetAttribute(a.src, whichLevel + "icon/signbot.gif").SetAttribute(a.alt, "MotD").UseClosingTag(false)))
.AppendChild(Node(a.li)
.AppendChild(Player(level))));
return extra;
}
inline Node ThePraDev::Player(Levels level)
{
ThePraDev a;
string whichLevel = ChooseLevel(level);
Node player = Node("div.player")
.AppendChild(Node("audio").SetAttribute("controls", "controls").SetAttribute("preload", "auto")
.AppendChild(Node("source").SetAttribute(a.src, whichLevel + "videoplayback.ogg").SetAttribute("type", "audio/ogg").SetContent("Your browser does not support the audio element.")));
return player;
}

108
TestWebGen/Utilities.h Normal file
View File

@ -0,0 +1,108 @@
#pragma once
#include <iostream>
#include <string>
#include <fstream>
#include <experimental/filesystem>
using namespace std;
using namespace std::experimental::filesystem::v1;
class Utilities
{
protected:
const string meta = "meta";
const string link = "link";
const string rel = "rel";
const string href = "href";
const string http_equiv = "http-equiv";
const string content = "content";
const string name = "name";
const string li = "li";
const string ul = "ul";
const string a = "a";
const string src = "src";
const string alt = "alt";
public:
static enum DeskOrMob
{
D, //Desktop part of the page
M //Mobile part of the page
};
DeskOrMob setDM = D;
enum Levels
{
ROOT,//Content at the index.html directory level
LEVEL1,//Content at the first directory
LEVEL2//Content at the second directory
};
enum Sites
{
DEV,//Build the thepra-dev.com
ART//Build the art.thepra-dev.com
};
enum PageType
{
NORMAL,
POST
};
static string ChooseLevel(Levels level);
static void FullFillContent(string link, string* desktop, string* mobile);
static string GetCurrentPath();
};
inline string Utilities::ChooseLevel(Levels level)
{
switch (level)
{
case Utilities::ROOT:return "";
break;
case Utilities::LEVEL1:return "../";
break;
case Utilities::LEVEL2:return "../../";
default:return "";
break;
}
}
inline void Utilities::FullFillContent(string link, string* desktop, string* mobile)
{
//link = "C:\\content\\index.txt"; //TODO find out a general way to scan the folder env
Utilities a = Utilities();
string line = "";
std::ifstream infile;
infile.open(link);
while (!infile.eof())
{
std::getline(infile, line);
if (line == "desktop")
{
line = "";
a.setDM = D;
}
if (a.setDM == D)
{
if (line == "mobile")
{
line = "";
a.setDM = M;
}
*desktop += line + "\n";
}
if (a.setDM == M)
{
*mobile += line + "\n";
}
}
infile.close();
}
inline string Utilities::GetCurrentPath()
{
path current = current_path();
string pathString = current.string();
//cout << pathString << endl;
return pathString;
}

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="dirent" version="1.13.1" targetFramework="native" />
</packages>

8
TestWebGen/stdafx.cpp Normal file
View File

@ -0,0 +1,8 @@
// stdafx.cpp : source file that includes just the standard includes
// TestWebGen.pch will be the pre-compiled header
// stdafx.obj will contain the pre-compiled type information
#include "stdafx.h"
// TODO: reference any additional headers you need in STDAFX.H
// and not in this file

15
TestWebGen/stdafx.h Normal file
View File

@ -0,0 +1,15 @@
// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//
#pragma once
#include "targetver.h"
#include <stdio.h>
#include <tchar.h>
// TODO: reference additional headers your program requires here

8
TestWebGen/targetver.h Normal file
View File

@ -0,0 +1,8 @@
#pragma once
// Including SDKDDKVer.h defines the highest available Windows platform.
// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
#include <SDKDDKVer.h>

96
TestWebGen/tests.cpp Normal file
View File

@ -0,0 +1,96 @@
#include "stdafx.h"
#include <iostream>
#include "CTML.h"
#include <chrono>
// std chrono has the worst namespace abuse i've ever seen, so therefore, i'm typedeffing
typedef std::chrono::high_resolution_clock high_res_clock;
typedef std::chrono::milliseconds millis;
using namespace CTML;
// tests if two strings are equivelent to each other
bool assert_strings_equal(const std::string& left, const std::string& right) {
return (left == right);
}
// this test ensures that HTML inside of the content is escaped correctly.
void run_escape_test() {
// what the node's to string should be equal to
const auto htmlString = "<a class=\"button\">&lt;script&gt;alert(\"ha ha hacked!\")&lt;/script&gt;</a>";
Node node("a.button", "<script>alert(\"ha ha hacked!\")</script>");
// the node's string output
const auto nodeString = node.ToString(Readability::SINGLE_LINE, 0);
auto test = assert_strings_equal(htmlString, nodeString);
std::cout << "Escape Test " << ((test) ? "passed!" : "failed!") << std::endl <<
"HTML Output: " << nodeString << std::endl <<
// use a double end line at the end for spacing between tests
"Expected Output: " << htmlString << std::endl << std::endl;
}
// this test ensures that the HTML document created is equal to a correct HTML5 document
void run_document_test() {
// what the document's to string should be equal to
const auto htmlString = "<!DOCTYPE html><html><head></head><body><h1>&lt;test!&gt;</h1></body></html>";
Document doc;
// the string output of the document
doc.AddNodeToBody(Node("h1", "<test!>"));
const auto docString = doc.ToString(Readability::SINGLE_LINE);
auto test = assert_strings_equal(htmlString, docString);
std::cout << "Document Test " << ((test) ? "passed!" : "failed!") << std::endl <<
"HTML Output: " << docString << std::endl <<
// use a double end line at the end for spacing between tests
"Expected Output: " << htmlString << std::endl << std::endl;
}
// this test checks if the classes provided are correctly stored
void run_class_test() {
const auto classString = "test classes are fun";
Node testNode("a#test.test.classes.are.fun");
// get the test node's classlist.
const auto classList = testNode.GetAttribute("class");
bool test = assert_strings_equal(classString, classList);
std::cout << "Class Test " << ((test) ? "passed!" : "failed!") << std::endl <<
"Class Output: " << classList << std::endl <<
// use a double end line at the end for spacing between tests
"Expected Output: " << classString << std::endl << std::endl;
}
// this test checks if the attributes provided are correctly stored and gotten
void run_attribute_test() {
const auto attrOutput = "testAttr1";
const auto attr2Output = "testAttr2";
const auto attr3Output = "";
Node testNode("a");
// set two attributes on the node
testNode.SetAttribute("attr1", "testAttr1").SetAttribute("attr2", "testAttr2");
// get each attribute's output
const auto attrOut = testNode.GetAttribute("attr1");
const auto attr2Out = testNode.GetAttribute("attr2");
const auto attr3Out = testNode.GetAttribute("attr3");
// test each string
auto test1 = assert_strings_equal(attrOutput, attrOut);
auto test2 = assert_strings_equal(attr2Output, attr2Out);
auto test3 = assert_strings_equal(attr3Output, attr3Out);
std::cout << "Class Test " << ((test1 && test2 && test3) ? "passed!" : "failed!") << std::endl <<
"Attr 1 Output: " << attrOut << std::endl <<
"Expected Output: " << attrOutput << std::endl <<
"Attr 2 Output: " << attr2Out << std::endl <<
"Expected Output: " << attr2Output << std::endl <<
"Attr 3 Output: " << attr3Out << std::endl <<
// use a double end line at the end for spacing between tests
"Expected Output: " << attr3Output << std::endl << std::endl;
}
int main() {
high_res_clock::time_point begin = high_res_clock::now();
run_escape_test();
run_document_test();
run_class_test();
run_attribute_test();
high_res_clock::time_point end = high_res_clock::now();
millis ms = std::chrono::duration_cast<millis>(end - begin);
std::cout << "Tests ran in " << ms.count() << "ms" << std::endl;
return 0;
}