Skip to content

Commit 137bed3

Browse files
committed
added test case
1 parent a01bc7d commit 137bed3

File tree

6 files changed

+196
-27
lines changed

6 files changed

+196
-27
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,3 +68,4 @@ This program obviously is not perfect, hence there are some limitations that sho
6868
* Comments done with `/* */` aren't stored for re-attachment as they are often inside clauses
6969

7070
## Credits
71+
* The test configuration `./tests/example_configurations/pms_example_config.nix` comes from (here)[https://perfectmediaserver.com/02-tech-stack/nixos/configuration.nix/]

nix_tree/section_screens.py

Lines changed: 31 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,9 @@ def on_input_submitted(self, user_input: Input.Submitted):
8080
user_input: Input.Submitted - the choice of the user
8181
"""
8282

83-
clean_input: str = re.sub(r"(\[)(\s*)", "[ ", user_input.value)
84-
clean_input: str = re.sub(r"(\s*)(\])", " ]", clean_input)
83+
clean_input: str = re.sub(r"\"", "'", user_input.value)
84+
clean_input = re.sub(r"(\[)(\s*)", "[ ", clean_input)
85+
clean_input = re.sub(r"(\s*)(\])", " ]", clean_input)
8586
self.dismiss(clean_input)
8687

8788

@@ -118,12 +119,17 @@ def on_input_submitted(self, user_input: Input.Submitted) -> None:
118119
If the section is being added to the root node, the second method of addition would put a dot at the
119120
start hence the if statement
120121
"""
121-
self.__node.node.add(user_input.value)
122-
if self.__node.node.is_root:
123-
self.dismiss([f"Section {user_input.value} added"])
122+
123+
if re.search(r"[^a-zA-Z_]", user_input.value):
124+
self.notify("You have entered invalid character(s) for the name of the group, not adding", title="error adding section", severity="error")
125+
self.dismiss(None)
124126
else:
125-
full_path = '.'.join(work_out_full_path(self.__node.node, []))
126-
self.dismiss([f"Section {full_path}.{user_input.value} added"])
127+
self.__node.node.add(user_input.value)
128+
if self.__node.node.is_root:
129+
self.dismiss([f"Section {user_input.value} added"])
130+
else:
131+
full_path = '.'.join(work_out_full_path(self.__node.node, []))
132+
self.dismiss([f"Section {full_path}.{user_input.value} added"])
127133

128134

129135
class AddScreenInteger(ModalScreen[str]):
@@ -275,7 +281,7 @@ def on_input_submitted(self, path: Input.Submitted) -> None:
275281
not get added
276282
"""
277283

278-
def handle_return_from_variable_addition(data: tuple[str | list, Types | None] | None) -> None:
284+
def handle_return_from_variable_addition(data: tuple[str, Types | None] | None) -> None:
279285
"""Takes the data from variable addition and returns it back to the main class
280286
281287
Args:
@@ -286,18 +292,15 @@ def handle_return_from_variable_addition(data: tuple[str | list, Types | None] |
286292
"""
287293

288294
if data:
289-
if isinstance(data[0], list): # It's a group being added
290-
self.dismiss(data[0])
291-
return
292-
if data[1] == Types.LIST and (not re.search(r"\A\[.+]\Z", data[0])):
293-
self.notify("You lost a bracket! Not updating")
295+
if data[1] == Types.LIST and (not re.search(r"^\s*\[[^\]]*\]\s*$", data[0])):
296+
self.notify("You lost (or gained) a bracket! Not updating", title="error adding option", severity="error")
294297
if type_as_defined:
295298
self.app.push_screen(RecommendedTypeOrChooseType(type_as_defined),
296299
handle_return_from_variable_addition)
297300
else:
298301
self.app.push_screen(AddScreenVariableSelection(), handle_return_from_variable_addition)
299-
elif data[1] == Types.STRING and (not re.search(r"\A'.+'\Z", data[0])):
300-
self.notify("You lost a speech mark! Not updating")
302+
elif data[1] == Types.STRING and (not re.search(r"^\s*'[^']*'\s*$", data[0])):
303+
self.notify("You lost (or gained) a speech mark! Not updating", title="error adding option", severity="error")
301304
if type_as_defined:
302305
self.app.push_screen(RecommendedTypeOrChooseType(type_as_defined),
303306
handle_return_from_variable_addition)
@@ -319,16 +322,20 @@ def handle_return_from_variable_addition(data: tuple[str | list, Types | None] |
319322
else:
320323
self.app.pop_screen()
321324

322-
self.__path = path.value
323-
path_leading_up_to_section = ""
324-
if not self.__node.node.is_root:
325-
path_leading_up_to_section: str = '.'.join(work_out_full_path(self.__node.node, [])) + "."
326-
type_as_defined: tuple[Types, str] | None = self.__options.check_type(path_leading_up_to_section + path.value)
327-
if type_as_defined:
328-
self.app.push_screen(RecommendedTypeOrChooseType(type_as_defined),
329-
handle_return_from_variable_addition)
325+
if re.search(r"[^a-zA-Z_]", path.value):
326+
self.notify("You have entered invalid character(s) for the path of your option, not adding", title="error adding option", severity="error")
327+
self.dismiss(None)
330328
else:
331-
self.app.push_screen(AddScreenVariableSelection(), handle_return_from_variable_addition)
329+
self.__path = path.value
330+
path_leading_up_to_section = ""
331+
if not self.__node.node.is_root:
332+
path_leading_up_to_section: str = '.'.join(work_out_full_path(self.__node.node, [])) + "."
333+
type_as_defined: tuple[Types, str] | None = self.__options.check_type(path_leading_up_to_section + path.value)
334+
if type_as_defined:
335+
self.app.push_screen(RecommendedTypeOrChooseType(type_as_defined),
336+
handle_return_from_variable_addition)
337+
else:
338+
self.app.push_screen(AddScreenVariableSelection(), handle_return_from_variable_addition)
332339

333340
def on_button_pressed(self):
334341
"""If a button has been pressed then a group has been added and hence the group addition function

nix_tree/variable_screens.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,14 +69,14 @@ def on_input_submitted(self, new_data: Input.Submitted) -> None:
6969

7070
if self.__value != new_data.value:
7171
if self.__type == Types.LIST and (not re.search(r"^\s*\[[^\]]*\]\s*$", new_data.value)):
72-
self.notify("You lost (or gained) a bracket! Not updating")
72+
self.notify("You lost (or gained) a bracket! Not updating", title="error changing option", severity="error")
7373
self.app.pop_screen()
7474
elif self.__type == Types.STRING and (not re.search(r"^\s*'[^']*'\s*$", new_data.value)):
75-
self.notify("You lost (or gained) a speech mark! Not updating")
75+
self.notify("You lost (or gained) a speech mark! Not updating", title="error changing option", severity="error")
7676
self.app.pop_screen()
7777
else:
7878
clean_input: str = re.sub(r"\"", "'", new_data.value)
79-
clean_input = re.sub(r"(\[)(\s*)", "[ ", new_data.value)
79+
clean_input = re.sub(r"(\[)(\s*)", "[ ", clean_input)
8080
clean_input = re.sub(r"(\s*)(\])", " ]", clean_input)
8181
self.__node.node.label = self.__path.split(".")[-1] + "=" + clean_input
8282
if self.__node.node.data:
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
/* credit: https://perfectmediaserver.com/02-tech-stack/nixos/configuration.nix/
2+
slightly modified on line 66 where a small section has been removed */
3+
4+
# Edit this configuration file to define what should be installed on
5+
# your system. Help is available in the configuration.nix(5) man page
6+
# and in the NixOS manual (accessible by running `nixos-help`).
7+
8+
{ config, pkgs, ... }:
9+
10+
{
11+
imports =
12+
[ # Include the results of the hardware scan.
13+
./hardware-configuration.nix
14+
];
15+
16+
# Use the systemd-boot EFI boot loader.
17+
boot.loader.systemd-boot.enable = true;
18+
boot.loader.efi.canTouchEfiVariables = true;
19+
20+
boot.supportedFilesystems = [ "zfs" ];
21+
boot.zfs.forceImportRoot = false;
22+
#boot.zfs.extraPools = [ "zfstest" ];
23+
services.zfs.autoScrub.enable = true;
24+
25+
time.timeZone = "America/New_York";
26+
27+
users.users.alex = {
28+
isNormalUser = true;
29+
extraGroups = [ "wheel" "docker" ];
30+
};
31+
users.users.alex.openssh.authorizedKeys.keyFiles = [
32+
/etc/nixos/ssh/authorized_keys
33+
];
34+
users.users.root.openssh.authorizedKeys.keyFiles = [
35+
/etc/nixos/ssh/authorized_keys
36+
];
37+
38+
environment.systemPackages = with pkgs; [
39+
docker-compose
40+
htop
41+
hddtemp
42+
intel-gpu-tools
43+
iotop
44+
lm_sensors
45+
mergerfs
46+
mc
47+
ncdu
48+
nmap
49+
nvme-cli
50+
sanoid
51+
snapraid
52+
tdns-cli
53+
tmux
54+
tree
55+
vim
56+
wget
57+
smartmontools
58+
e2fsprogs # badblocks
59+
];
60+
61+
networking = {
62+
firewall.enable = false;
63+
hostName = "testnix";
64+
hostId = "e5f2dc02";
65+
interfaces = {
66+
enp1s0 = {
67+
useDHCP = false;
68+
};
69+
};
70+
defaultGateway = "10.42.0.254";
71+
nameservers = [ "10.42.0.253" ];
72+
};
73+
74+
services.openssh = {
75+
enable = true;
76+
settings.PasswordAuthentication = false;
77+
settings.PermitRootLogin = "yes";
78+
};
79+
services.tailscale.enable = true;
80+
81+
virtualisation = {
82+
docker = {
83+
enable = true;
84+
autoPrune = {
85+
enable = true;
86+
dates = "weekly";
87+
};
88+
};
89+
};
90+
91+
services = {
92+
xserver = {
93+
enable = true;
94+
displayManager = {
95+
lightdm.enable = true;
96+
defaultSession = "xfce";
97+
#defaultSession = "xfce+bspwm";
98+
};
99+
desktopManager.xfce.enable = true;
100+
windowManager.bspwm.enable = true;
101+
};
102+
};
103+
104+
nix = {
105+
settings = {
106+
experimental-features = [ "nix-command" "flakes" ];
107+
warn-dirty = false;
108+
};
109+
};
110+
111+
services.samba-wsdd.enable = true; # make shares visible for windows 10 clients
112+
services.samba = {
113+
enable = true;
114+
securityType = "user";
115+
extraConfig = ''
116+
workgroup = KTZ
117+
server string = testnix
118+
netbios name = testnix
119+
security = user
120+
guest ok = yes
121+
guest account = nobody
122+
map to guest = bad user
123+
load printers = no
124+
'';
125+
shares = {
126+
zfstest = {
127+
path = "/mnt/zfstest";
128+
browseable = "yes";
129+
"read only" = "no";
130+
"guest ok" = "yes";
131+
"create mask" = "0644";
132+
"directory mask" = "0755";
133+
"force user" = "alex";
134+
"force group" = "users";
135+
};
136+
};
137+
};
138+
139+
system.copySystemConfiguration = true;
140+
system.stateVersion = "23.05";
141+
142+
}

tests/test_comment_collecting.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,11 @@ def test_yasu_example_config():
1717

1818
comment_handler = CommentHandling(Path("./tests/example_configurations/yasu_example_config.nix"))
1919
assert "{3: [('# Include the results of the hardware scan.\\n', False)], 10: [('# Define your hostname.\\n', False)], 20: [('#audio', True)], 35: [('# Steam\\n', False)]}".replace("\"", '"') == str(comment_handler.get_comments_for_attaching())
20+
21+
def test_pms_example_config():
22+
"""
23+
Checks if all comments are collected correctly in pms_example_config.nix configuration
24+
"""
25+
26+
comment_handler = CommentHandling(Path("./tests/example_configurations/pms_example_config.nix"))
27+
assert "{6: [('# Edit this configuration file to define what should be installed on', True), ('# your system. Help is available in the configuration.nix(5) man page', True), ('# and in the NixOS manual (accessible by running `nixos-help`).', True)], 11: [('# Include the results of the hardware scan.\\n', False)], 16: [('# Use the systemd-boot EFI boot loader.', True)], 22: [('#boot.zfs.extraPools = [ \"zfstest\" ];', True)], 57: [('# badblocks\\n', False)], 97: [('#defaultSession = \"xfce+bspwm\";', True)], 110: [('# make shares visible for windows 10 clients\\n', False)]}".replace("\"", '"') == str(comment_handler.get_comments_for_attaching())

tests/test_tree_building.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99

1010
SHORTENED_DEFAULT_TREE = """{}{ |--headers=[ config, pkgs, ... ]}{ |--imports=[ ./hardware-configuration.nix ]}{ boot}{ loader}{ grub}{ |--enable=true}{ |--device='/dev/sda'}{ |--useOSProber=true}{ networking}{ |--hostName='nixos'}{ networkmanager}{ |--enable=true}{ time}{ |--timeZone='Europe/London'}{ i18n}{ |--defaultLocale='en_GB.UTF-8'}{ services}{ xserver}{ |--enable=true}{ programs}{ firefox}{ |--enable=true}{ nixpkgs}{ config}{ |--allowUnfree=true}{ environment}{ |--systemPackages=[ (pkgs).vim (pkgs).git ]}{ system}{ |--stateVersion='23.11'}"""
1111

12+
PMS_TREE = """{}{ |--headers=[ config, pkgs, ... ]}{ |--imports=[ ./hardware-configuration.nix ]}{ boot}{ loader}{ systemd-boot}{ |--enable=true}{ efi}{ |--canTouchEfiVariables=true}{ |--supportedFilesystems=[ 'zfs' ]}{ zfs}{ |--forceImportRoot=false}{ services}{ zfs}{ autoScrub}{ |--enable=true}{ openssh}{ |--enable=true}{ settings}{ |--PasswordAuthentication=false}{ |--PermitRootLogin='yes'}{ tailscale}{ |--enable=true}{ xserver}{ |--enable=true}{ displayManager}{ lightdm}{ |--enable=true}{ |--defaultSession='xfce'}{ desktopManager}{ xfce}{ |--enable=true}{ windowManager}{ bspwm}{ |--enable=true}{ samba-wsdd}{ |--enable=true}{ samba}{ |--enable=true}{ |--securityType='user'}{ |--extraConfig='' workgroup = KTZ server string = testnix netbios name = testnix security = user guest ok = yes guest account = nobody map to guest = bad user load printers = no ''}{ shares}{ zfstest}{ |--path='/mnt/zfstest'}{ |--browseable='yes'}{ |--'read only'='no'}{ |--'guest ok'='yes'}{ |--'create mask'='0644'}{ |--'directory mask'='0755'}{ |--'force user'='alex'}{ |--'force group'='users'}{ time}{ |--timeZone='America/New_York'}{ users}{ users}{ alex}{ |--isNormalUser=true}{ |--extraGroups=[ 'wheel' 'docker' ]}{ openssh}{ authorizedKeys}{ |--keyFiles=[ /etc/nixos/ssh/authorized_keys ]}{ users}{ root}{ openssh}{ authorizedKeys}{ |--keyFiles=[ /etc/nixos/ssh/authorized_keys ]}{ environment}{ |--systemPackages=[ (pkgs).docker-compose (pkgs).htop (pkgs).hddtemp (pkgs).intel-gpu-tools (pkgs).iotop (pkgs).lm_sensors (pkgs).mergerfs (pkgs).mc (pkgs).ncdu (pkgs).nmap (pkgs).nvme-cli (pkgs).sanoid (pkgs).snapraid (pkgs).tdns-cli (pkgs).tmux (pkgs).tree (pkgs).vim (pkgs).wget (pkgs).smartmontools (pkgs).e2fsprogs (pkgs). ]}{ networking}{ firewall}{ |--enable=false}{ |--hostName='testnix'}{ |--hostId='e5f2dc02'}{ interfaces}{ enp1s0}{ |--useDHCP=false}{ |--defaultGateway='10.42.0.254'}{ |--nameservers=[ '10.42.0.253' ]}{ virtualisation}{ docker}{ |--enable=true}{ autoPrune}{ |--enable=true}{ |--dates='weekly'}{ nix}{ settings}{ |--experimental-features=[ 'nix-command' 'flakes' ]}{ |--warn-dirty=false}{ system}{ |--copySystemConfiguration=true}{ |--stateVersion='23.05'}"""
13+
1214
def tree_output(node: Node, append: str = "", output_string: str = "") -> str:
1315
"""
1416
Outputs the tree in an easier format for testing - its a really similar function to tree.quick_display()
@@ -48,3 +50,12 @@ def test_tree_for_shortened_default_config():
4850
tree = DecomposerTree()
4951
Decomposer(file_path=Path("./tests/example_configurations/shortened_default.nix"), tree=tree)
5052
assert SHORTENED_DEFAULT_TREE == tree_output(tree.get_root())
53+
54+
def test_tree_for_pms_example_config():
55+
"""
56+
Checks if the tree generator functions in decomposer and tree work as expected for the pms example config
57+
"""
58+
59+
tree = DecomposerTree()
60+
Decomposer(file_path=Path("./tests/example_configurations/pms_example_config.nix"), tree=tree)
61+
assert PMS_TREE == tree_output(tree.get_root())

0 commit comments

Comments
 (0)