Newer
Older
dom-persist / source / dom_persist_tests.d
/**
	COPYRIGHT © 2024 JOHN PEARCEY
	Distributed under the Boost Software License, Version 1.0.
		See accompanying file LICENSE.txt or copy at
		https://www.boost.org/LICENSE_1_0.txt
*/
module dom_persist_tests;

import std.stdio;

import dom_persist;
import nodecode;
import consolecolors; //https://code.dlang.org/packages/console-colors/1.1.2

import d2sqlite3;	// https://d2sqlite3.dpldocs.info/v1.0.0/d2sqlite3.database.Database.this.html
						// https://dlang-community.github.io/d2sqlite3/d2sqlite3.html


version(unittest){	

	//stuff only compiled for unittests
	string sqlite_filename = "dom_persist_test.db";

	void assertNDRecord( Row row, long id, string e_data, long pid, TreeNodeType tnt ){
	
		assert( id == row.peek!long(0) );
		assert( e_data == row.peek!string(1) );
		assert( pid == row.peek!long(2) );
		assert( tnt == getTreeNodeType( row.peek!int(3) ) );
	
	}

	class Timer{
		
		static ulong getCount(){
			asm{
				naked	;
				rdtsc	;
				ret	;
			}
		}

		ulong starttime;

		this() { starttime = getCount(); }
		
		~this(){
			ulong endtime = getCount();
			writefln("elapsed time ( %d to %d ) = %d", starttime, endtime, endtime - starttime);
		}
	}

}

unittest {
	
	writeln( "Testing tree creation" );
	
	db_drop( sqlite_filename );
	assert( !db_exists( sqlite_filename ) );

	Database db = db_create( sqlite_filename, 1 );

	assert( db_exists( sqlite_filename ) );	
	assert(db.tableColumnMetadata("params", "ID") == TableColumnMetadata("INTEGER", "BINARY", false, true, true));

	Tree_Db.db_create_schema( db );
	assert(db.tableColumnMetadata("doctree", "ID") == TableColumnMetadata("INTEGER", "BINARY", false, true, true));

	db.close();

}

unittest{
	
	auto db = Database( sqlite_filename );
	Tree_Db tree = Tree_Db.createTree( db, "mytree" );

	TreeNode tree_node = tree.getTreeRoot();
	NodeData nd = tree_node.node_data;
	
	assert( nd.pid == 0);
	assert( nd.e_data == "mytree");
	
	//bDebug_out = true;
	
	debug_out("tree_node-1: ", &tree_node);

	// flush the empty tree
	tree.flush();

	ResultRange results = db.execute( "select ID, e_data, p_id, t_id from doctree where id=1" );
	Row row = results.front();

	assertNDRecord( row, 1, "mytree", 0, TreeNodeType.tree );

	//bDebug_out = true;
	
	debug_out("tree_node-2: ", &tree_node);
	
	tree_node.appendChild( TreeNodeType.docType, "html" );
	auto tn_html = tree_node.appendChild( TreeNodeType.element, "html" );
	
	auto tn_head = tn_html.appendChild( TreeNodeType.element, "head" );
	tn_head.appendChild( TreeNodeType.comment, "This is my comment" );
	
	auto tn_body = tn_html.appendChild( TreeNodeType.element, "body" );
	
	tn_body.appendChild( TreeNodeType.text, "This is some text" );
	tn_body.appendChild( TreeNodeType.text, " with more text" );
	tn_body.appendChild( TreeNodeType.element, "input" );
	
	
	tree.flush();

	//bDebug_out = false;

	string html_out = tree.getTreeAsText( );	
	//writeln( html_out );
	assert( html_out == "<DOCTYPE html><html><head><!--This is my comment--></head><body>This is some text with more text<input/></body></html>");
	

}


unittest{

	writeln( "Testing DocOrderIterator" );

	auto db = Database( sqlite_filename );
	TreeNameID[] tree_list = Tree_Db.getTreeList( db );	
	Tree_Db tree = Tree_Db.loadTree( db, tree_list[0].tree_id );
	
	TreeNode tree_node = tree.getTreeRoot();
	
	DocOrderIterator it = new DocOrderIterator( tree_node );
	int i=0;
	TreeNode nxt;
	while( (nxt=it.nextNode) !is null ){		
		switch(i){
		case 0:
			assert( nxt.node_data.type == TreeNodeType.tree );
			break;
			
		case 1:
			assert( nxt.node_data.type == TreeNodeType.docType );
			break;

		case 2,3,5,8:
			assert( nxt.node_data.type == TreeNodeType.element );
			break;

		case 4:
			assert( nxt.node_data.type == TreeNodeType.comment );
			break;

		case 6,7:
			assert( nxt.node_data.type == TreeNodeType.text );
			break;

		default:
		}
		i+=1;
	}
}

unittest{

	writeln( "Testing tree loading" );

	auto db = Database( sqlite_filename );
		
	auto tree2 = Tree_Db.createTree( db, "AnotherTree" );
	tree2.flush();
	
	TreeNameID[] tree_list = Tree_Db.getTreeList( db );
	assert( tree_list.length==2 );
	
	Tree_Db tree = Tree_Db.loadTree( db, tree_list[0].tree_id );
	
	TreeNode tree_node = tree.getTreeRoot();
	NodeData nd_t = tree_node.node_data;
	assert( nd_t.ID == tree_list[0].tree_id );
	assert( nd_t.e_data == tree_list[0].name );
	assert( nd_t.pid == 0 );
	assert( nd_t.type == TreeNodeType.tree );

	TreeNode html_node;
	
	int i=0;
	foreach( node_ptr; tree_node.child_nodes ){		

		NodeData c_node = node_ptr.node_data;
		
		switch(i){
		case 0:
			assert( c_node.ID == 2 );
			assert( c_node.e_data == "html" );
			assert( c_node.pid == tree_list[0].tree_id );
			assert( c_node.type == TreeNodeType.docType );
			break;

		case 1:
			html_node = node_ptr;
			assert( c_node.ID == 3 );
			assert( c_node.e_data == "html" );
			assert( c_node.pid == tree_list[0].tree_id );
			assert( c_node.type == TreeNodeType.element );
			break;
		
		default:
		}
	
		i+=1;
	}
	
	string html_out = tree.getTreeAsText( );	
	assert( html_out == "<DOCTYPE html><html><head><!--This is my comment--></head><body>This is some text with more text<input/></body></html>");

	writeln( "Testing tree element insertion" );

	//get head element
	TreeNode tn_head = html_node.child_nodes[0];	
	
	//add an element to the head at position zero
	tn_head.insertChild( TreeNodeType.element, "script", 0 );	
	
	html_out = tree.getTreeAsText( );	
	assert( html_out == "<DOCTYPE html><html><head><script></script><!--This is my comment--></head><body>This is some text with more text<input/></body></html>");

	writeln( "Testing tree editing" );

	//edit the comment node (id=5)
	TreeNode e_comment = tree.getTreeNodeById( 5 );	
	e_comment.setData( "An edit took place" );
	
	html_out = tree.getTreeAsText( );	
	assert( html_out == "<DOCTYPE html><html><head><script></script><!--An edit took place--></head><body>This is some text with more text<input/></body></html>");

	//check that the database entry is unchanged
	auto results = db.execute( "select e_data from doctree where id=5" );
	foreach (row; results){		
		assert( "This is my comment" == row.peek!string(0) );
	}
	
	// save to database	
	tree.flush();
		
	//check db contents using a new tree
	Tree_Db tree3 = Tree_Db.loadTree( db, tree_list[0].tree_id );
	html_out = tree3.getTreeAsText( );	
	//writeln( html_out );
	assert( html_out == "<DOCTYPE html><html><head><script></script><!--An edit took place--></head><body>This is some text with more text<input/></body></html>");

	writeln("Testing test element move");
	
	//use the original tree to test a move the comment node	
	auto tn_body = tn_head.nextSibling();
	e_comment.moveNode( tn_body, 0 );
	html_out = tree.getTreeAsText( );	
	assert( html_out == "<DOCTYPE html><html><head><script></script></head><body><!--An edit took place-->This is some text with more text<input/></body></html>");
	
	//test that it flushes correctly
	tree.flush();
	auto result = db.execute( "select id, e_data, p_id, t_id from doctree where id=5" );		
	assertNDRecord( result.front(), 5, "An edit took place", tn_body.node_data.ID, TreeNodeType.comment );
	
	cwriteln("<red>TODO:</red> Test multiple moveNode");		
}

unittest{
	
	writeln( "Testing tree element deletion" );


	auto db = Database( sqlite_filename );
	
	TreeNameID[] tree_list = Tree_Db.getTreeList( db );
	assert( tree_list.length==2 );
	
	Tree_Db tree = Tree_Db.loadTree( db, tree_list[0].tree_id );
	string html_out = tree.getTreeAsText( );	
	//writeln( html_out );
	assert( html_out == "<DOCTYPE html><html><head><script></script></head><body><!--An edit took place-->This is some text with more text<input/></body></html>");
	
	TreeNode tn_head = tree.getTreeRoot().getChildAt(1).getChildAt(0);
	tn_head.getChildAt(0).deleteNode();	//delete the script node
	
	html_out = tree.getTreeAsText( );	
	assert( html_out == "<DOCTYPE html><html><head></head><body><!--An edit took place-->This is some text with more text<input/></body></html>");
	
	//check that the database record still exists
	auto result = db.execute( "select id, e_data, p_id, t_id from doctree where id=11" );		
	assertNDRecord( result.front(), 11, "script", tn_head.node_data.ID, TreeNodeType.element );
	
	tree.flush();
	
	//reload and check
	tree = Tree_Db.loadTree( db, tree_list[0].tree_id );
	html_out = tree.getTreeAsText( );	
	assert( html_out == "<DOCTYPE html><html><head></head><body><!--An edit took place-->This is some text with more text<input/></body></html>");
	
			
}

unittest{
	
	writeln( "Testing attributes" );


	auto db = Database( sqlite_filename );
	
	TreeNameID[] tree_list = Tree_Db.getTreeList( db );
	assert( tree_list.length==2 );
	
	Tree_Db tree = Tree_Db.loadTree( db, tree_list[0].tree_id );
	string html_out = tree.getTreeAsText( );	
	//writeln( html_out );
	assert( html_out == "<DOCTYPE html><html><head></head><body><!--An edit took place-->This is some text with more text<input/></body></html>");
	
	TreeNode tn_body = tree.getTreeRoot().getChildAt(1).getChildAt(1);
	tn_body.setAttribute( "border", "solid red 1px");
	
	assert( tn_body.hasAttributes );	
	tree.flush();
	
	html_out = tree.getTreeAsText( );
	//writeln( html_out );
	assert( html_out == "<DOCTYPE html><html><head></head><body border=\"solid red 1px\" ><!--An edit took place-->This is some text with more text<input/></body></html>");
	
	tn_body.setAttribute( "border", "solid red 2px");
	tn_body.setAttribute( "v-align", "top");
	html_out = tree.getTreeAsText( );
	//writeln( html_out );
	if( html_out != "<DOCTYPE html><html><head></head><body border=\"solid red 2px\" v-align=\"top\" ><!--An edit took place-->This is some text with more text<input/></body></html>" &&
		html_out != "<DOCTYPE html><html><head></head><body v-align=\"top\" border=\"solid red 2px\" ><!--An edit took place-->This is some text with more text<input/></body></html>" ){
		// the order of the attributes does not matter, either one will do.
		assert(false);
	}
	
	tn_body.removeAttribute("border");
	tree.flush();
	
	html_out = tree.getTreeAsText( );
	assert( html_out == "<DOCTYPE html><html><head></head><body v-align=\"top\" ><!--An edit took place-->This is some text with more text<input/></body></html>");
	
}



/*unittest{


	int[] a1;
	
	for(int i=0; i<10000; i+=1){
		a1 ~= i;
	}
	
	{
		scope t = new Timer();
		
		for(int i=0; i<10000; i+=1){
			removeAt!int( a1, 0 );
		}
	}
}*/