Skip to content

Commit 08bba55

Browse files
CopilotMikefly123
andauthored
Move jokes from config.json to separate jokes.json file (#318)
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Mikefly123 <61564344+Mikefly123@users.noreply.github.com>
1 parent adcc36c commit 08bba55

File tree

8 files changed

+279
-66
lines changed

8 files changed

+279
-66
lines changed

circuitpython-workspaces/flight-software/src/pysquared/config/config.py

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ class Config:
2525
Loads configuration from a JSON file, validates values, and provides
2626
methods to update configuration settings. Supports both temporary (RAM-only)
2727
and permanent (file-persisted) updates. Delegates radio-related validation
28-
and updates to the RadioConfig class.
28+
and updates to the RadioConfig class. Jokes are loaded from a separate
29+
jokes.json file in the same directory as the config file.
2930
3031
Attributes:
3132
config_file (str): Path to the configuration JSON file.
@@ -35,7 +36,7 @@ class Config:
3536
detumble_enable_z (bool): Enable detumbling on Z axis.
3637
detumble_enable_x (bool): Enable detumbling on X axis.
3738
detumble_enable_y (bool): Enable detumbling on Y axis.
38-
jokes (list[str]): List of jokes for the cubesat.
39+
jokes (list[str]): List of jokes for the cubesat (loaded from jokes.json).
3940
debug (bool): Debug mode flag.
4041
heating (bool): Heating system enabled flag.
4142
normal_temp (int): Normal operating temperature.
@@ -68,8 +69,8 @@ def __init__(self, config_path: str) -> None:
6869
config_path (str): Path to the configuration JSON file.
6970
7071
Raises:
71-
FileNotFoundError: If the configuration file does not exist.
72-
json.JSONDecodeError: If the configuration file is not valid JSON.
72+
FileNotFoundError: If the configuration file or jokes.json does not exist.
73+
json.JSONDecodeError: If the configuration file or jokes.json is not valid JSON.
7374
"""
7475

7576
self.config_file = config_path
@@ -83,7 +84,23 @@ def __init__(self, config_path: str) -> None:
8384
self.detumble_enable_z: bool = json_data["detumble_enable_z"]
8485
self.detumble_enable_x: bool = json_data["detumble_enable_x"]
8586
self.detumble_enable_y: bool = json_data["detumble_enable_y"]
86-
self.jokes: list[str] = json_data["jokes"]
87+
88+
# Load jokes from separate jokes.json file in the same directory
89+
# Extract directory from config_path using string operations (CircuitPython compatible)
90+
if "/" in config_path:
91+
config_dir = "/".join(config_path.split("/")[:-1])
92+
else:
93+
config_dir = "."
94+
95+
# Construct jokes path
96+
if config_dir == ".":
97+
jokes_path = "jokes.json"
98+
else:
99+
jokes_path = config_dir + "/jokes.json"
100+
101+
with open(jokes_path, "r") as f:
102+
self.jokes: list[str] = json.loads(f.read())
103+
87104
self.debug: bool = json_data["debug"]
88105
self.heating: bool = json_data["heating"]
89106
self.normal_temp: int = json_data["normal_temp"]
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
{
2+
"battery_voltage": 5.2,
3+
"critical_battery_voltage": 6.6,
4+
"cubesat_name": "Orpheus",
5+
"current_draw": 240.5,
6+
"debug": true,
7+
"degraded_battery_voltage": 7.0,
8+
"detumble_enable_x": true,
9+
"detumble_enable_y": true,
10+
"detumble_enable_z": true,
11+
"heating": false,
12+
"last_battery_temp": 20.0,
13+
"longest_allowable_sleep_time": 600,
14+
"normal_battery_temp": 1,
15+
"normal_battery_voltage": 6.9,
16+
"normal_charge_current": 0.5,
17+
"normal_micro_temp": 20,
18+
"normal_temp": 20,
19+
"radio": {
20+
"fsk": {
21+
"broadcast_address": 255,
22+
"modulation_type": 0,
23+
"node_address": 1
24+
},
25+
"license": "",
26+
"lora": {
27+
"ack_delay": 0.2,
28+
"coding_rate": 8,
29+
"cyclic_redundancy_check": true,
30+
"max_output": true,
31+
"spreading_factor": 8,
32+
"transmit_power": 23
33+
},
34+
"modulation": "LoRa",
35+
"start_time": 80000,
36+
"transmit_frequency": 437.4
37+
},
38+
"reboot_time": 3600,
39+
"repeat_code": "RP",
40+
"sleep_duration": 30,
41+
"super_secret_code": "ABCD",
42+
"turbo_clock": false
43+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
[
2+
"Hey it is pretty cold up here, did someone forget to pay the electric bill?",
3+
"sudo rf - rf*",
4+
"Why did the astronaut break up with his girlfriend? He needed space.",
5+
"Why did the sun go to school? To get a little brighter.",
6+
"why is the mall called the mall? because instead of going to one store you go to them all",
7+
"Alien detected. Blurring photo...",
8+
"Wait it is all open source? Always has been... www.github.com/proveskit",
9+
"What did 0 say to 1? You're a bit too much.",
10+
"Pleiades - Orpheus has been recently acquired by the Onion News Network",
11+
"This jokesat was brought to you by the Bronco Space Ministry of Labor and Job Placement",
12+
"Catch you on the next pass!",
13+
"Pleiades - Orpheus was not The Impostor",
14+
"Sorry for messing with your long-exposure astrophoto!",
15+
"Better buy a telescope. Wanna see me. Buy a telescope. Gonna be in space.",
16+
"According to all known laws of aviation, there is no way bees should be able to fly...",
17+
"You lost the game ",
18+
"Bobby Tables is a good friend of mine",
19+
"Why did the computer cross the road? To get a byte to eat!",
20+
"Why are the astronauts not hungry when they got to space? They had a big launch.",
21+
"Why did the computer get glasses? To improve its web sight!",
22+
"What are computers favorite snacks? Chips!",
23+
"Wait! I think I see a White 2019 Subaru Crosstrek 2.0i Premium",
24+
"IS THAT A SUPRA?!",
25+
"Finally escaped the LA Traffic",
26+
"My CubeSat is really good at jokes, but its delivery is always delayed.",
27+
"exec order 66",
28+
"I had a joke about UDP, but I am not sure if you'd get it.",
29+
"I am not saying FSK modulation is the best way to send jokes, but at least it is never monotone!",
30+
"I am sorry David, I am afrain I can not do that.",
31+
"My memory is volatile like RAM, so it only makes sense that I forget things.",
32+
"Imagine it gets stuck and just keeps repeating this joke every 2 mins",
33+
"Check Engine: Error Code 404: Joke Not Found",
34+
"CQ CQ KN6NAQ ... KN6NAT are you out there?",
35+
"Woah is that the Launcher Orbiter?????",
36+
"Everything in life is a spring if you think hard enough!"
37+
]

cpython-workspaces/flight-software-unit-tests/src/unit-tests/files/config.test.json

Lines changed: 0 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -9,43 +9,6 @@
99
"detumble_enable_y": true,
1010
"detumble_enable_z": true,
1111
"heating": false,
12-
"jokes": [
13-
"Hey it is pretty cold up here, did someone forget to pay the electric bill?",
14-
"sudo rf - rf*",
15-
"Why did the astronaut break up with his girlfriend? He needed space.",
16-
"Why did the sun go to school? To get a little brighter.",
17-
"why is the mall called the mall? because instead of going to one store you go to them all",
18-
"Alien detected. Blurring photo...",
19-
"Wait it is all open source? Always has been... www.github.com/proveskit",
20-
"What did 0 say to 1? You're a bit too much.",
21-
"Pleiades - Orpheus has been recently acquired by the Onion News Network",
22-
"This jokesat was brought to you by the Bronco Space Ministry of Labor and Job Placement",
23-
"Catch you on the next pass!",
24-
"Pleiades - Orpheus was not The Impostor",
25-
"Sorry for messing with your long-exposure astrophoto!",
26-
"Better buy a telescope. Wanna see me. Buy a telescope. Gonna be in space.",
27-
"According to all known laws of aviation, there is no way bees should be able to fly...",
28-
"You lost the game ",
29-
"Bobby Tables is a good friend of mine",
30-
"Why did the computer cross the road? To get a byte to eat!",
31-
"Why are the astronauts not hungry when they got to space? They had a big launch.",
32-
"Why did the computer get glasses? To improve its web sight!",
33-
"What are computers favorite snacks? Chips!",
34-
"Wait! I think I see a White 2019 Subaru Crosstrek 2.0i Premium",
35-
"IS THAT A SUPRA?!",
36-
"Finally escaped the LA Traffic",
37-
"My CubeSat is really good at jokes, but its delivery is always delayed.",
38-
"exec order 66",
39-
"I had a joke about UDP, but I am not sure if you'd get it.",
40-
"I am not saying FSK modulation is the best way to send jokes, but at least it is never monotone!",
41-
"I am sorry David, I am afrain I can not do that.",
42-
"My memory is volatile like RAM, so it only makes sense that I forget things.",
43-
"Imagine it gets stuck and just keeps repeating this joke every 2 mins",
44-
"Check Engine: Error Code 404: Joke Not Found",
45-
"CQ CQ KN6NAQ ... KN6NAT are you out there?",
46-
"Woah is that the Launcher Orbiter?????",
47-
"Everything in life is a spring if you think hard enough!"
48-
],
4912
"last_battery_temp": 20.0,
5013
"longest_allowable_sleep_time": 600,
5114
"normal_battery_temp": 1,
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
[
2+
"Hey it is pretty cold up here, did someone forget to pay the electric bill?",
3+
"sudo rf - rf*",
4+
"Why did the astronaut break up with his girlfriend? He needed space.",
5+
"Why did the sun go to school? To get a little brighter.",
6+
"why is the mall called the mall? because instead of going to one store you go to them all",
7+
"Alien detected. Blurring photo...",
8+
"Wait it is all open source? Always has been... www.github.com/proveskit",
9+
"What did 0 say to 1? You're a bit too much.",
10+
"Pleiades - Orpheus has been recently acquired by the Onion News Network",
11+
"This jokesat was brought to you by the Bronco Space Ministry of Labor and Job Placement",
12+
"Catch you on the next pass!",
13+
"Pleiades - Orpheus was not The Impostor",
14+
"Sorry for messing with your long-exposure astrophoto!",
15+
"Better buy a telescope. Wanna see me. Buy a telescope. Gonna be in space.",
16+
"According to all known laws of aviation, there is no way bees should be able to fly...",
17+
"You lost the game ",
18+
"Bobby Tables is a good friend of mine",
19+
"Why did the computer cross the road? To get a byte to eat!",
20+
"Why are the astronauts not hungry when they got to space? They had a big launch.",
21+
"Why did the computer get glasses? To improve its web sight!",
22+
"What are computers favorite snacks? Chips!",
23+
"Wait! I think I see a White 2019 Subaru Crosstrek 2.0i Premium",
24+
"IS THAT A SUPRA?!",
25+
"Finally escaped the LA Traffic",
26+
"My CubeSat is really good at jokes, but its delivery is always delayed.",
27+
"exec order 66",
28+
"I had a joke about UDP, but I am not sure if you'd get it.",
29+
"I am not saying FSK modulation is the best way to send jokes, but at least it is never monotone!",
30+
"I am sorry David, I am afrain I can not do that.",
31+
"My memory is volatile like RAM, so it only makes sense that I forget things.",
32+
"Imagine it gets stuck and just keeps repeating this joke every 2 mins",
33+
"Check Engine: Error Code 404: Joke Not Found",
34+
"CQ CQ KN6NAQ ... KN6NAT are you out there?",
35+
"Woah is that the Launcher Orbiter?????",
36+
"Everything in life is a spring if you think hard enough!"
37+
]

cpython-workspaces/flight-software-unit-tests/src/unit-tests/other/other_test_config.py

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
"detumble_enable_z": bool,
2020
"detumble_enable_x": bool,
2121
"detumble_enable_y": bool,
22-
"jokes": list,
2322
"debug": bool,
2423
"heating": bool,
2524
"normal_temp": int,
@@ -274,14 +273,6 @@ def test_field_types(config_data):
274273
for field in bool_fields:
275274
assert isinstance(config_data[field], bool), f"{field} must be a boolean"
276275

277-
# Test list fields
278-
list_fields = ["jokes"]
279-
for field in list_fields:
280-
assert isinstance(config_data[field], list), f"{field} must be a list"
281-
assert all(isinstance(item, str) for item in config_data[field]), (
282-
f"All items in {field} must be strings"
283-
)
284-
285276
# Test radio config
286277
assert isinstance(config_data["radio"], dict), "radio must be a dictionary"
287278

@@ -368,18 +359,3 @@ def test_current_draw_positive(config_data):
368359
negative current draw would imply an impossible scenario in this context.
369360
"""
370361
assert config_data["current_draw"] >= 0, "current_draw cannot be negative"
371-
372-
373-
def test_lists_not_empty(config_data):
374-
"""Tests that list fields are not empty.
375-
376-
Args:
377-
config_data: Fixture providing the loaded configuration data.
378-
379-
This test specifically checks that the `jokes` list is not empty and that
380-
all its elements are strings, ensuring valid content for this field.
381-
"""
382-
assert len(config_data["jokes"]) > 0, "jokes list cannot be empty"
383-
assert all(isinstance(joke, str) for joke in config_data["jokes"]), (
384-
"All jokes must be strings"
385-
)
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
"""Unit tests for the jokes.json file.
2+
3+
This module contains unit tests to ensure that jokes.json exists, is valid JSON,
4+
and contains the expected structure and content.
5+
"""
6+
7+
import json
8+
from pathlib import Path
9+
10+
import pytest
11+
12+
13+
@pytest.fixture
14+
def jokes_data():
15+
"""Loads and provides jokes data from jokes.json.
16+
17+
Returns:
18+
list: The jokes loaded from jokes.json.
19+
"""
20+
workspace_root = Path(__file__).parent.parent.parent
21+
jokes_path = workspace_root / "jokes.json"
22+
with open(jokes_path, "r") as f:
23+
return json.loads(f.read())
24+
25+
26+
def test_jokes_file_exists():
27+
"""Tests that jokes.json exists.
28+
29+
This test verifies that the `jokes.json` file is present in the expected
30+
location within the project structure.
31+
"""
32+
workspace_root = Path(__file__).parent.parent.parent
33+
jokes_path = workspace_root / "jokes.json"
34+
assert jokes_path.exists(), "jokes.json file not found"
35+
36+
37+
def test_jokes_is_valid_json():
38+
"""Tests that jokes.json is valid JSON.
39+
40+
This test ensures that the content of `jokes.json` can be successfully
41+
parsed as a JSON array.
42+
"""
43+
workspace_root = Path(__file__).parent.parent.parent
44+
jokes_path = workspace_root / "jokes.json"
45+
with open(jokes_path, "r") as f:
46+
data = json.loads(f.read())
47+
assert isinstance(data, list), "Jokes file is not a valid JSON array"
48+
49+
50+
def test_jokes_not_empty(jokes_data):
51+
"""Tests that jokes list is not empty.
52+
53+
Args:
54+
jokes_data: Fixture providing the loaded jokes data.
55+
56+
This test specifically checks that the jokes list is not empty and that
57+
all its elements are strings, ensuring valid content.
58+
"""
59+
assert len(jokes_data) > 0, "jokes list cannot be empty"
60+
assert all(isinstance(joke, str) for joke in jokes_data), (
61+
"All jokes must be strings"
62+
)
63+
64+
65+
def test_jokes_are_strings(jokes_data):
66+
"""Tests that all jokes are strings.
67+
68+
Args:
69+
jokes_data: Fixture providing the loaded jokes data.
70+
71+
This test ensures that each joke in the list is a non-empty string.
72+
"""
73+
for i, joke in enumerate(jokes_data):
74+
assert isinstance(joke, str), f"Joke at index {i} is not a string"
75+
assert len(joke) > 0, f"Joke at index {i} is an empty string"

0 commit comments

Comments
 (0)