Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit1688a7b

Browse files
author
Yurii A.
committed
WIP: add suggested tests skeleton
* refactor extract_snippets.py to take arguments from command line* add logging to extract_snippets.py script* add suggested CMakeLists.txt* add google test library, add example refactoring for 2sat and aho korasick tests
1 parent6eecd4a commit1688a7b

File tree

6 files changed

+286
-41
lines changed

6 files changed

+286
-41
lines changed

‎test/.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
/*.h
1+
include/snippets/
2+
build/

‎test/CMakeLists.txt

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
cmake_minimum_required(VERSION 3.30 FATAL_ERROR)
2+
3+
project(cp-algorithms LANGUAGES CXX)
4+
5+
# generating snippets
6+
set(SNIPPETS_DIR${CMAKE_CURRENT_SOURCE_DIR}/include/snippets)
7+
find_package(Python3 3.10 REQUIRED COMPONENTS Interpreter)
8+
execute_process(
9+
COMMAND
10+
${Python3_EXECUTABLE}
11+
"${CMAKE_CURRENT_SOURCE_DIR}/scripts/extract_snippets.py"
12+
--src-dir=${CMAKE_CURRENT_SOURCE_DIR}/../src
13+
--target-dir=${SNIPPETS_DIR}
14+
--remove-prev-target-dir
15+
COMMAND_ERROR_IS_FATAL ANY
16+
)
17+
18+
# loading googletest
19+
include(FetchContent)
20+
FetchContent_Declare(
21+
googletest
22+
GIT_REPOSITORY https://github.com/google/googletest.git
23+
GIT_TAG v1.17.0
24+
)
25+
# For Windows: Prevent overriding the parent project's compiler/linker settings
26+
set(gtest_force_shared_crtONCACHEBOOL"" FORCE)
27+
FetchContent_MakeAvailable(googletest)
28+
include(GoogleTest)
29+
30+
set(CMAKE_CXX_STANDARD 20)
31+
set(CMAKE_CXX_STANDARD_REQUIREDON)
32+
set(CMAKE_CXX_EXTENSIONSOFF)
33+
34+
file(GLOB_RECURSE SNIPPETS_SOURCES CONFIGURE_DEPENDS${SNIPPETS_DIR}/*.h)
35+
file(GLOB_RECURSE TEST_SOURCES CONFIGURE_DEPENDS src/test_*.cpp)
36+
37+
add_executable(main${TEST_SOURCES}${SNIPPETS_SOURCES})
38+
target_link_libraries(mainPRIVATE GTest::gtest_main GTest::gtest GTest::gmock)
39+
target_include_directories(mainPRIVATE${CMAKE_CURRENT_SOURCE_DIR}/include)
40+
41+
enable_testing()
42+
gtest_discover_tests(main)

‎test/extract_snippets.py

Lines changed: 0 additions & 40 deletions
This file was deleted.

‎test/scripts/extract_snippets.py

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
importargparse
2+
importre
3+
importos
4+
importsys
5+
importshutil
6+
importlogging
7+
fromtypingimportList,Optional
8+
fromdataclassesimportdataclass
9+
10+
11+
@dataclass
12+
classSnippet:
13+
name:str
14+
lines:List[str]
15+
16+
17+
defwrite_snippet(target_dir:os.PathLike,snippet:Snippet):
18+
assertos.path.exists(target_dir)andos.path.isdir(target_dir)
19+
20+
file_name=f'{snippet.name}.h'
21+
withopen(os.path.join(target_dir,file_name),'w',encoding='utf-8')asf:
22+
f.writelines(snippet.lines)
23+
24+
25+
defextract_snippets(filepath:os.PathLike)->List[Snippet]:
26+
withopen(filepath,'r',encoding='utf-8')asf:
27+
lines=f.readlines()
28+
29+
snippets= []
30+
31+
snippet_start=re.compile(r"^```\{.cpp\s+file=(\S+)\}$")
32+
snippet_end=re.compile(r"^```$")
33+
34+
snippet_start_line:Optional[int]=None
35+
snippet_name:Optional[str]=None
36+
37+
forline_idx,lineinenumerate(lines):
38+
match_snippet_start=snippet_start.match(line)
39+
match_snippet_end=snippet_end.match(line)
40+
assertnot (match_snippet_startandmatch_snippet_end)
41+
42+
ifmatch_snippet_start:
43+
assertsnippet_start_lineisNone
44+
assertsnippet_nameisNone
45+
46+
snippet_start_line=line_idx
47+
snippet_name=match_snippet_start.group(1)
48+
elifmatch_snippet_end:
49+
ifsnippet_start_lineisnotNone:
50+
assertsnippet_start_lineisnotNone
51+
assertsnippet_nameisnotNone
52+
53+
snippet=lines[snippet_start_line+1:line_idx]
54+
55+
snippets.append(Snippet(name=snippet_name,lines=snippet))
56+
57+
snippet_start_line=None
58+
snippet_name=None
59+
60+
returnsnippets
61+
62+
63+
defmain(args:argparse.Namespace)->None:
64+
src_dir=args.src_dir
65+
target_dir=args.target_dir
66+
67+
logging.info(f'--src-dir="{src_dir}"')
68+
logging.info(f'--target-dir="{target_dir}"')
69+
70+
assertos.path.isdir(src_dir)
71+
72+
ifargs.remove_prev_target_dirandos.path.exists(target_dir):
73+
logging.info(f'Script launched with --remove-prev-target-dir flag')
74+
logging.info(f'Removing --target-dir="{target_dir}"')
75+
shutil.rmtree(target_dir)
76+
77+
ifnotos.path.exists(target_dir):
78+
logging.info(
79+
f'--target-dir="{target_dir}" does not exist, creating')
80+
os.makedirs(target_dir,exist_ok=False)
81+
assertos.path.isdir(
82+
target_dir),f'Failed to create --target-dir: "{target_dir}"'
83+
84+
snippets= []
85+
86+
forsubdir,_,filesinos.walk(src_dir):
87+
forfilenameinfiles:
88+
iffilename.lower().endswith('.md'):
89+
filepath=os.path.join(subdir,filename)
90+
logging.debug(f'Extracting snippets from{filename}')
91+
snippets.extend(extract_snippets(filepath))
92+
93+
n_snippets=len(snippets)
94+
forsnippet_idx,snippetinenumerate(snippets,start=1):
95+
logging.debug(
96+
f'({snippet_idx}/{n_snippets}) writing snippet{snippet.name} to "{target_dir}"')
97+
write_snippet(target_dir,snippet)
98+
99+
logging.info(
100+
f'All done,{n_snippets} snippets have been written to "{target_dir}"')
101+
102+
103+
if__name__=='__main__':
104+
parser=argparse.ArgumentParser(
105+
description='Recursively extracts specially annotation cpp code snippets from src dir with .md files')
106+
107+
parser.add_argument('--src-dir',type=str,required=True,
108+
help='path to the directory with .md source to recursively look for cpp snippets with {.cpp file=...} annotation')
109+
parser.add_argument('--target-dir',type=str,required=True,
110+
help='path to the resulting directory with .h snippets extracted from src-dir')
111+
parser.add_argument('--remove-prev-target-dir',action='store_true',
112+
help='remove --target-dir prior to generating snippets')
113+
114+
logging_level_names=list(logging.getLevelNamesMapping().keys())
115+
assert'INFO'inlogging_level_names
116+
parser.add_argument('--logging-level',type=str,choices=logging_level_names,
117+
default='INFO',help='script logging level')
118+
119+
args=parser.parse_args()
120+
121+
logging.basicConfig(
122+
stream=sys.stdout,
123+
format='%(asctime)s %(module)-15s - [%(levelname)-6s] - %(message)s',
124+
datefmt='%H:%M:%S',
125+
level=args.logging_level
126+
)
127+
128+
main(args)

‎test/src/test_2sat_new.cpp

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
#include<gtest/gtest.h>
2+
#include<gmock/gmock.h>
3+
4+
#include<vector>
5+
usingnamespacestd;
6+
7+
#include"snippets/2sat.h"
8+
9+
namespace
10+
{
11+
TEST(TwoSAT, ExampleUsage)
12+
{
13+
TwoSatSolver::example_usage();
14+
}
15+
16+
TEST(TwoSAT, ArticleExample)
17+
{
18+
TwoSatSolversolver(3);// a, b, c
19+
solver.add_disjunction(0,false,1,true);// a v not b
20+
solver.add_disjunction(0,true,1,false);// not a v b
21+
solver.add_disjunction(0,true,1,true);// not a v not b
22+
solver.add_disjunction(0,false,2,true);// a v not c
23+
EXPECT_TRUE(solver.solve_2SAT());
24+
auto expected = vector<bool>{{false,false,false}};
25+
EXPECT_EQ(solver.assignment, expected);
26+
}
27+
28+
TEST(TwoSAT, Unsatisfiable)
29+
{
30+
TwoSatSolversolver(2);// a, b
31+
solver.add_disjunction(0,false,1,false);// a v b
32+
solver.add_disjunction(0,false,1,true);// a v not b
33+
solver.add_disjunction(0,true,1,false);// not a v b
34+
solver.add_disjunction(0,true,1,true);// not a v not b
35+
EXPECT_FALSE(solver.solve_2SAT());
36+
}
37+
38+
TEST(TwoSAT, OtherSatisfiableExample)
39+
{
40+
TwoSatSolversolver(4);// a, b, c, d
41+
solver.add_disjunction(0,false,1,true);// a v not b
42+
solver.add_disjunction(0,true,2,true);// not a v not c
43+
solver.add_disjunction(0,false,1,false);// a v b
44+
solver.add_disjunction(3,false,2,true);// d v not c
45+
solver.add_disjunction(3,false,0,true);// d v not a
46+
EXPECT_TRUE(solver.solve_2SAT());
47+
// two solutions
48+
auto expected_1 = vector<bool>{{true,true,false,true}};
49+
auto expected_2 = vector<bool>{{true,false,false,true}};
50+
EXPECT_THAT(solver.assignment, ::testing::AnyOf(expected_1, expected_2));
51+
}
52+
53+
}// namespace

‎test/src/test_aho_korasick_new.cpp

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
#include<gtest/gtest.h>
2+
3+
#include<vector>
4+
#include<string>
5+
#include<iostream>
6+
usingnamespacestd;
7+
8+
namespace {
9+
10+
namespaceTrie {
11+
#include"snippets/aho_corasick_trie_definition.h"
12+
#include"snippets/aho_corasick_trie_add.h"
13+
}// namespace Trie
14+
15+
namespaceAutomaton {
16+
#include"snippets/aho_corasick_automaton.h"
17+
}// namespace Automation
18+
19+
TEST(AhoKorasick, TrieAddString)
20+
{
21+
usingnamespaceTrie;
22+
23+
vector<string> set = {"a","to","tea","ted","ten","i","in","inn"};
24+
for (string s : set) {
25+
add_string(s);
26+
}
27+
28+
EXPECT_EQ(trie.size(),11);
29+
}
30+
31+
TEST(AhoKorasick, TrieAutomation)
32+
{
33+
usingnamespaceAutomaton;
34+
35+
vector<string> set = {"a","ab","bab","bc","bca","c","caa"};
36+
for (string s : set) {
37+
add_string(s);
38+
}
39+
EXPECT_EQ(t.size(),11);
40+
41+
int v =0;
42+
v =go(v,'a');
43+
EXPECT_TRUE(t[v].output);
44+
v =go(v,'b');
45+
EXPECT_TRUE(t[v].output);
46+
v =go(v,'c');
47+
EXPECT_TRUE(t[v].output);
48+
v =go(v,'d');
49+
EXPECT_FALSE(t[v].output);
50+
EXPECT_EQ(v,0);
51+
v =go(v,'b');
52+
EXPECT_FALSE(t[v].output);
53+
v =go(v,'a');
54+
EXPECT_FALSE(t[v].output);
55+
v =go(v,'a');
56+
EXPECT_TRUE(t[v].output);
57+
v =go(v,'b');
58+
EXPECT_TRUE(t[v].output);
59+
}
60+
61+
}// namespace

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp