Added testing! call kraken like so ./kraken --test ../path/to/test/name_of_test_without_extention This will make kraken compile and run name_of_test_without_extention.krak and compare the output it generates on stdout to name_of_test_without_extention.expected_results. If they pass, then it records the pass, if not, it records the failure and saves the intermediate files generated. It has revealed some bugs which I will fix in upcoming commits.
This commit is contained in:
@@ -6,7 +6,7 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
|||||||
|
|
||||||
set( MY_INCLUDES ${PROJECT_SOURCE_DIR}/include)
|
set( MY_INCLUDES ${PROJECT_SOURCE_DIR}/include)
|
||||||
|
|
||||||
set( MY_SOURCES main.cpp src/Parser.cpp src/LALRParser.cpp src/GraphStructuredStack.cpp src/RNGLRParser.cpp src/ParseAction.cpp src/ParseRule.cpp src/Symbol.cpp src/StringReader.cpp src/State.cpp src/util.cpp src/Lexer.cpp src/RegEx.cpp src/RegExState.cpp src/Table.cpp src/ASTData.cpp src/ASTTransformation.cpp src/CGenerator.cpp src/Type.cpp src/Importer.cpp )
|
set( MY_SOURCES main.cpp src/Parser.cpp src/LALRParser.cpp src/GraphStructuredStack.cpp src/RNGLRParser.cpp src/ParseAction.cpp src/ParseRule.cpp src/Symbol.cpp src/StringReader.cpp src/State.cpp src/util.cpp src/Lexer.cpp src/RegEx.cpp src/RegExState.cpp src/Table.cpp src/ASTData.cpp src/ASTTransformation.cpp src/CGenerator.cpp src/Type.cpp src/Importer.cpp src/Tester.cpp )
|
||||||
|
|
||||||
add_custom_target(STDLibCopy ALL)
|
add_custom_target(STDLibCopy ALL)
|
||||||
add_custom_command(TARGET STDLibCopy POST_BUILD
|
add_custom_command(TARGET STDLibCopy POST_BUILD
|
||||||
|
|||||||
31
include/Tester.h
Normal file
31
include/Tester.h
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
#ifndef TESTER_H
|
||||||
|
#define TESTER_H
|
||||||
|
|
||||||
|
class Tester {
|
||||||
|
public:
|
||||||
|
Tester(std::string krakenInvocation, std::string krakenGrammerLocation);
|
||||||
|
~Tester();
|
||||||
|
int ssystem(std::string command);
|
||||||
|
bool run(std::string fileName);
|
||||||
|
bool compareFiles(std::string file1Path, std::string file2Path);
|
||||||
|
void cleanExtras(std::string fileName);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string krakenInvocation;
|
||||||
|
std::string krakenGrammerLocation;
|
||||||
|
std::string removeCmd;
|
||||||
|
std::string resultsExtention;
|
||||||
|
std::string expectedExtention;
|
||||||
|
std::string krakenExtention;
|
||||||
|
std::string shell;
|
||||||
|
std::string changePermissions;
|
||||||
|
std::string redirect;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
@@ -9,6 +9,8 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <fstream>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
std::string intToString(int theInt);
|
std::string intToString(int theInt);
|
||||||
std::string replaceExEscape(std::string first, std::string search, std::string replace);
|
std::string replaceExEscape(std::string first, std::string search, std::string replace);
|
||||||
@@ -16,6 +18,9 @@ std::string strSlice(std::string str, int begin, int end);
|
|||||||
int findPerenEnd(std::string str, int i);
|
int findPerenEnd(std::string str, int i);
|
||||||
std::vector<std::string> split(const std::string &str, char delim);
|
std::vector<std::string> split(const std::string &str, char delim);
|
||||||
std::string join(const std::vector<std::string> &strVec, std::string joinStr);
|
std::string join(const std::vector<std::string> &strVec, std::string joinStr);
|
||||||
|
std::string readFile(std::istream &file);
|
||||||
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool contains(std::vector<T> vec, T item) {
|
bool contains(std::vector<T> vec, T item) {
|
||||||
for (auto i : vec)
|
for (auto i : vec)
|
||||||
|
|||||||
20
main.cpp
20
main.cpp
@@ -16,16 +16,34 @@
|
|||||||
#include "CGenerator.h"
|
#include "CGenerator.h"
|
||||||
|
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include "Tester.h"
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
std::vector<std::string> includePaths;
|
std::vector<std::string> includePaths;
|
||||||
includePaths.push_back(""); //Local
|
includePaths.push_back(""); //Local
|
||||||
|
|
||||||
if (argc == 2 && std::string(argv[1]) == "--test") {
|
if (argc >= 2 && std::string(argv[1]) == "--test") {
|
||||||
StringReader::test();
|
StringReader::test();
|
||||||
RegEx::test();
|
RegEx::test();
|
||||||
Lexer::test();
|
Lexer::test();
|
||||||
//std::cout << strSlice("123", 0, -1) << std::endl;
|
//std::cout << strSlice("123", 0, -1) << std::endl;
|
||||||
|
if (argc >= 3) {
|
||||||
|
std::string testResults, line;
|
||||||
|
int passed = 0, failed = 0;
|
||||||
|
Tester test(argv[0], "../krakenGrammer.kgm");
|
||||||
|
for (int i = 2; i < argc; i++) {
|
||||||
|
bool result = test.run(argv[i]);
|
||||||
|
if (result)
|
||||||
|
line = std::string(argv[i]) + "\t\tpassed!\n", passed++;
|
||||||
|
else
|
||||||
|
line = std::string(argv[i]) + "\t\tFAILED!\n", failed++;
|
||||||
|
std::cout << line << std::endl;
|
||||||
|
testResults += line;
|
||||||
|
}
|
||||||
|
std::cout << "===========Done Testing===========" << std::endl;
|
||||||
|
std::cout << testResults << std::endl;
|
||||||
|
std::cout << "Test results: " << passed << "/" << passed+failed << std::endl;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
std::string krakenDir = argv[0];
|
std::string krakenDir = argv[0];
|
||||||
|
|||||||
69
src/Tester.cpp
Normal file
69
src/Tester.cpp
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
#include "Tester.h"
|
||||||
|
|
||||||
|
Tester::Tester(std::string krakenInvocation, std::string krakenGrammerLocation) : krakenInvocation(krakenInvocation), krakenGrammerLocation(krakenGrammerLocation) {
|
||||||
|
//initlization list
|
||||||
|
removeCmd = "rm";
|
||||||
|
resultsExtention = ".results";
|
||||||
|
expectedExtention = ".expected_results";
|
||||||
|
krakenExtention = ".krak";
|
||||||
|
changePermissions = "chmod 755";
|
||||||
|
shell = "sh";
|
||||||
|
redirect = ">";
|
||||||
|
}
|
||||||
|
|
||||||
|
Tester::~Tester() {
|
||||||
|
//Nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
int Tester::ssystem(std::string command) {
|
||||||
|
return system(command.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Tester::cleanExtras(std::string fileName) {
|
||||||
|
ssystem(removeCmd + " " + fileName);
|
||||||
|
ssystem(removeCmd + " " + fileName + krakenExtention + "out*");
|
||||||
|
ssystem(removeCmd + " " + fileName + krakenExtention + ".c");
|
||||||
|
ssystem(removeCmd + " " + fileName + ".sh");
|
||||||
|
ssystem(removeCmd + " " + fileName + resultsExtention);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Tester::run(std::string fileName) {
|
||||||
|
std::cout << "Testing: " << fileName << " with " << krakenInvocation << " and " << krakenGrammerLocation << std::endl;
|
||||||
|
|
||||||
|
cleanExtras(fileName);
|
||||||
|
|
||||||
|
ssystem(changePermissions + " " + fileName);
|
||||||
|
ssystem(krakenInvocation + " " + fileName + krakenExtention + " " + krakenGrammerLocation + " " + fileName);
|
||||||
|
ssystem(shell + " " + fileName + ".sh");
|
||||||
|
ssystem(fileName + " " + redirect + " " + fileName + resultsExtention);
|
||||||
|
|
||||||
|
bool result = compareFiles(fileName + expectedExtention, fileName + resultsExtention);
|
||||||
|
|
||||||
|
//If the test was succesful, we don't need all the extra files
|
||||||
|
if (result)
|
||||||
|
cleanExtras(fileName);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Tester::compareFiles(std::string file1Path, std::string file2Path) {
|
||||||
|
std::ifstream file1, file2;
|
||||||
|
file1.open(file1Path);
|
||||||
|
if (!file1.is_open()) {
|
||||||
|
std::cout << file1Path << " could not be opened!" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
file2.open(file2Path);
|
||||||
|
if (!file2.is_open()) {
|
||||||
|
std::cout << file2Path << " could not be opened!" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string file1contents = readFile(file1);
|
||||||
|
std::string file2contents = readFile(file2);
|
||||||
|
|
||||||
|
// std::cout << "file1: " << file1contents << std::endl;
|
||||||
|
// std::cout << "file2: " << file2contents << std::endl;
|
||||||
|
// std::cout << "comp: " << file1contents.compare(file2contents) << std::endl;
|
||||||
|
return file1contents.compare(file2contents) == 0;
|
||||||
|
}
|
||||||
@@ -71,4 +71,13 @@ std::string join(const std::vector<std::string> &strVec, std::string joinStr) {
|
|||||||
return joinedStr;
|
return joinedStr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string readFile(std::istream &file) {
|
||||||
|
std::string line, contents;
|
||||||
|
while(file.good()) {
|
||||||
|
getline(file, line);
|
||||||
|
contents.append(line+"\n");
|
||||||
|
}
|
||||||
|
return contents;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
5
tests/OperatorOverloadTest.expected_results
Normal file
5
tests/OperatorOverloadTest.expected_results
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
3 9
|
||||||
|
6 18
|
||||||
|
Subtraction
|
||||||
|
3 9
|
||||||
|
-97 -61
|
||||||
64
tests/OperatorOverloadTest.krak
Normal file
64
tests/OperatorOverloadTest.krak
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
import io;
|
||||||
|
|
||||||
|
typedef Vec2 {
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
|
||||||
|
void print() {
|
||||||
|
print(x);
|
||||||
|
print(" ");
|
||||||
|
print(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec2 add(Vec2 other) {
|
||||||
|
Vec2 toReturn;
|
||||||
|
toReturn.x = x + other.x;
|
||||||
|
toReturn.y = y + other.y;
|
||||||
|
print();
|
||||||
|
return toReturn;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec2 subtract(Vec2 other) {
|
||||||
|
Vec2 toReturn;
|
||||||
|
toReturn.x = x - other.x;
|
||||||
|
toReturn.y = y - other.y;
|
||||||
|
print();
|
||||||
|
return toReturn;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec2 operator+(Vec2 other) {
|
||||||
|
return add(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
Vec2 operator-(Vec2 lhs, Vec2 rhs) {
|
||||||
|
return lhs.subtract(rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
Vec2 vector1;
|
||||||
|
Vec2 vector2;
|
||||||
|
vector1.x = 3;
|
||||||
|
vector1.y = 9;
|
||||||
|
vector2 = vector1;
|
||||||
|
/* NOTE COMMENT
|
||||||
|
Vec2 vector3;
|
||||||
|
vector3.x = vector1.x + vector2.x;
|
||||||
|
vector3.y = vector1.y + vector2.y;
|
||||||
|
vector2.print();
|
||||||
|
*/
|
||||||
|
Vec2 addition = vector1 + vector2;
|
||||||
|
print("\n");
|
||||||
|
addition.print();
|
||||||
|
print("\nSubtraction\n");
|
||||||
|
vector2.x = 100;
|
||||||
|
vector2.y = 70;
|
||||||
|
Vec2 subtraction = vector1 - vector2;
|
||||||
|
print("\n");
|
||||||
|
print(subtraction.x); print(" "); print(subtraction.y);
|
||||||
|
|
||||||
|
print("\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
1
tests/RecursiveTest.expected_results
Normal file
1
tests/RecursiveTest.expected_results
Normal file
@@ -0,0 +1 @@
|
|||||||
|
5
|
||||||
14
tests/RecursiveTest.krak
Normal file
14
tests/RecursiveTest.krak
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import io;
|
||||||
|
|
||||||
|
int fibanacci(int num) {
|
||||||
|
if (num < 2)
|
||||||
|
return 1;
|
||||||
|
return fibanacci(num-1) + fibanacci(num-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
print(fibanacci(4));
|
||||||
|
print("\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
1
tests/functionTemplateTest.expected_results
Normal file
1
tests/functionTemplateTest.expected_results
Normal file
@@ -0,0 +1 @@
|
|||||||
|
22
|
||||||
14
tests/functionTemplateTest.krak
Normal file
14
tests/functionTemplateTest.krak
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import io;
|
||||||
|
|
||||||
|
template <T>T addAndPrint(T a, T b) {
|
||||||
|
print(a+b);
|
||||||
|
return a+b;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
|
||||||
|
addAndPrint<int>(10,12);
|
||||||
|
print("\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
3
tests/memTest.expected_results
Normal file
3
tests/memTest.expected_results
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
11
|
||||||
|
Hello decent memory! Quite a nice feeling
|
||||||
|
|
||||||
27
tests/memTest.krak
Normal file
27
tests/memTest.krak
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import mem;
|
||||||
|
import io;
|
||||||
|
|
||||||
|
typedef AnObject {
|
||||||
|
int a;
|
||||||
|
int b;
|
||||||
|
char* c;
|
||||||
|
|
||||||
|
void print() {
|
||||||
|
print(a+b);
|
||||||
|
print("\n");
|
||||||
|
print(c);
|
||||||
|
print("\n");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
AnObject* ptr = new<AnObject>();
|
||||||
|
ptr->a = 4;
|
||||||
|
ptr->b = 7;
|
||||||
|
ptr->c = "Hello decent memory! Quite a nice feeling\n";
|
||||||
|
ptr->print();
|
||||||
|
delete<AnObject>(ptr);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
2
tests/moreComplexObjectTest.expected_results
Normal file
2
tests/moreComplexObjectTest.expected_results
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
742
|
||||||
|
1337
|
||||||
29
tests/moreComplexObjectTest.krak
Normal file
29
tests/moreComplexObjectTest.krak
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import io;
|
||||||
|
|
||||||
|
typedef firstObject {
|
||||||
|
int objectNum;
|
||||||
|
int other;
|
||||||
|
void print() {
|
||||||
|
print(other);
|
||||||
|
}
|
||||||
|
void printInd() {
|
||||||
|
print();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef Int int;
|
||||||
|
|
||||||
|
Int aliasNum;
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
firstObject wooObject;
|
||||||
|
wooObject.objectNum = 7;
|
||||||
|
print(wooObject.objectNum);
|
||||||
|
firstObject* objPtr = &wooObject;
|
||||||
|
objPtr->objectNum = 42;
|
||||||
|
print(objPtr->objectNum);
|
||||||
|
print("\n");
|
||||||
|
objPtr->other = 1337;
|
||||||
|
objPtr->printInd();
|
||||||
|
print("\n");
|
||||||
|
}
|
||||||
1
tests/objectOrderingTest.expected_results
Normal file
1
tests/objectOrderingTest.expected_results
Normal file
@@ -0,0 +1 @@
|
|||||||
|
12
|
||||||
27
tests/objectOrderingTest.krak
Normal file
27
tests/objectOrderingTest.krak
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import io;
|
||||||
|
|
||||||
|
typedef objectA {
|
||||||
|
int a;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef BigObject {
|
||||||
|
objectA a;
|
||||||
|
objectB b;
|
||||||
|
int add() {
|
||||||
|
return a.a + b.b;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef objectB {
|
||||||
|
int b;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
BigObject c;
|
||||||
|
c.a.a = 4;
|
||||||
|
c.b.b = 8;
|
||||||
|
print(c.add());
|
||||||
|
print("\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
1
tests/simpleFunctionTest.expected_results
Normal file
1
tests/simpleFunctionTest.expected_results
Normal file
@@ -0,0 +1 @@
|
|||||||
|
1919
|
||||||
14
tests/simpleFunctionTest.krak
Normal file
14
tests/simpleFunctionTest.krak
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import io;
|
||||||
|
|
||||||
|
int addAndPrintInt(int a, int b) {
|
||||||
|
print(a+b);
|
||||||
|
return a+b;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
|
||||||
|
print(addAndPrintInt(7,12));
|
||||||
|
print("\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
1
tests/simpleObjectTest.expected_results
Normal file
1
tests/simpleObjectTest.expected_results
Normal file
@@ -0,0 +1 @@
|
|||||||
|
57
|
||||||
18
tests/simpleObjectTest.krak
Normal file
18
tests/simpleObjectTest.krak
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
|
||||||
|
import io;
|
||||||
|
|
||||||
|
typedef FirstObject {
|
||||||
|
int objectNum;
|
||||||
|
void PrintSelf(int a) {
|
||||||
|
print(objectNum);
|
||||||
|
print(a);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
FirstObject wooObject;
|
||||||
|
wooObject.objectNum = 5;
|
||||||
|
wooObject.PrintSelf(7);
|
||||||
|
print("\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
8
tests/templateTest.expected_results
Normal file
8
tests/templateTest.expected_results
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
a: 5
|
||||||
|
b: 7
|
||||||
|
1337
|
||||||
|
a: 9
|
||||||
|
b: Hello Templates!
|
||||||
|
Woooo nesting!
|
||||||
|
From another file! Whoh!
|
||||||
|
1919
|
||||||
52
tests/templateTest.krak
Normal file
52
tests/templateTest.krak
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
import io;
|
||||||
|
import trivial_container;
|
||||||
|
|
||||||
|
typedef template <T> TemplateTest {
|
||||||
|
int a;
|
||||||
|
T b;
|
||||||
|
trivialContainer<T> c;
|
||||||
|
void print() {
|
||||||
|
print("a: ");
|
||||||
|
print(a);
|
||||||
|
print("\n");
|
||||||
|
print("b: ");
|
||||||
|
print(b);
|
||||||
|
print("\n");
|
||||||
|
c.print();
|
||||||
|
print("\n");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef MyInt int;
|
||||||
|
|
||||||
|
MyInt c;
|
||||||
|
|
||||||
|
|
||||||
|
template <T> T addAndPrint(T a, T b) {
|
||||||
|
print(a+b);
|
||||||
|
return a+b;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
TemplateTest<int> test;
|
||||||
|
TemplateTest<char*> test2;
|
||||||
|
test.a = 5;
|
||||||
|
test.b = 7;
|
||||||
|
test.c.data = 1337;
|
||||||
|
test2.a = 9;
|
||||||
|
test2.b = "Hello Templates!";
|
||||||
|
test2.c.data = "Woooo nesting!";
|
||||||
|
|
||||||
|
test.print();
|
||||||
|
test2.print();
|
||||||
|
|
||||||
|
trivialContainer<char*> testImport;
|
||||||
|
testImport.data = "From another file! Whoh!";
|
||||||
|
testImport.print();
|
||||||
|
print("\n");
|
||||||
|
|
||||||
|
print(addAndPrint<int>(7,12));
|
||||||
|
print("\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
1
tests/testArrayNotation.expected_results
Normal file
1
tests/testArrayNotation.expected_results
Normal file
@@ -0,0 +1 @@
|
|||||||
|
777
|
||||||
13
tests/testArrayNotation.krak
Normal file
13
tests/testArrayNotation.krak
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import io;
|
||||||
|
import mem;
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
int b;
|
||||||
|
int* a = &b;
|
||||||
|
a [ 0 ] = 7;
|
||||||
|
print(a [ 0 ] );
|
||||||
|
print(*a);
|
||||||
|
print(b);
|
||||||
|
print("\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user