@@ -703,6 +703,272 @@ def test_to_json(self):
703703 assert data ["name" ] == "levels"
704704 assert "beginner" in data ["proficiency-levels" ]
705705
706+ # Methods - from_dict
707+ def test_from_dict_simple (self ):
708+ """Test creating from dictionary with minimal details."""
709+
710+ # Arrange
711+ data : Dict [str , Any ] = {
712+ "owner" : "example.com" ,
713+ "name" : "levels" ,
714+ "description" : "Test levels" ,
715+ "version" : "1.0.0" ,
716+ "timestamp" : "2025-01-15T10:30:00+00:00" ,
717+ "certificate" : "--- cert ---" ,
718+ }
719+
720+ # Act
721+ level_list = ProficiencyLevelList .from_dict (data )
722+
723+ # Assert
724+ assert level_list .owner == "example.com"
725+ assert level_list .name == "levels"
726+ assert level_list .description == "Test levels"
727+ assert level_list .version == "1.0.0"
728+ assert level_list .timestamp .isoformat () == "2025-01-15T10:30:00+00:00"
729+ assert level_list .certificate == "--- cert ---"
730+
731+ def test_from_dict_levels_dependencies (self ):
732+ """Test creating from dictionary with levels and dependencies."""
733+
734+ # Arrange
735+ data : Dict [str , Any ] = {
736+ "owner" : "example.com" ,
737+ "name" : "levels" ,
738+ "version" : "1.0.0" ,
739+ "timestamp" : "2025-01-15T10:30:00+00:00" ,
740+ "certificate" : "cert" ,
741+ "proficiency-levels" : {
742+ "beginner" : {
743+ "description" : "Beginner level" ,
744+ "pretopics" : [],
745+ },
746+ "advanced" : {
747+ "description" : "Advanced level" ,
748+ "pretopics" : [],
749+ },
750+ },
751+ "dependencies" : {
752+ "math" : "example.com/math-topics@1.0.0" ,
753+ },
754+ }
755+
756+ # Act
757+ level_list = ProficiencyLevelList .from_dict (data )
758+
759+ # Assert
760+ assert len (level_list .levels ) == 2
761+ assert "beginner" in level_list .levels
762+ assert "advanced" in level_list .levels
763+ assert level_list .levels ["beginner" ].description == "Beginner level"
764+
765+ assert "math" in level_list .dependencies
766+ assert level_list .dependencies ["math" ].owner == "example.com"
767+ assert level_list .dependencies ["math" ].name == "math-topics"
768+ assert level_list .dependencies ["math" ].version == "1.0.0"
769+
770+ # Methods - from_json
771+ def test_from_json_basic (self ):
772+ """Test creating from JSON string."""
773+
774+ # Arrange
775+ json_str = json .dumps (
776+ {
777+ "owner" : "example.com" ,
778+ "name" : "levels" ,
779+ "description" : "Test levels" ,
780+ "version" : "1.0.0" ,
781+ "timestamp" : "2025-01-15T10:30:00+00:00" ,
782+ "certificate" : "--- cert ---" ,
783+ }
784+ )
785+
786+ # Act
787+ level_list = ProficiencyLevelList .from_json (json_str )
788+
789+ # Assert
790+ assert level_list .owner == "example.com"
791+ assert level_list .name == "levels"
792+ assert level_list .description == "Test levels"
793+ assert level_list .version == "1.0.0"
794+ assert level_list .timestamp .isoformat () == "2025-01-15T10:30:00+00:00"
795+ assert level_list .certificate == "--- cert ---"
796+
797+ def test_from_json_with_levels (self ):
798+ """Test creating from JSON string with levels and dependencies."""
799+
800+ # Arrange
801+ json_str = json .dumps (
802+ {
803+ "owner" : "example.com" ,
804+ "name" : "levels" ,
805+ "version" : "1.0.0" ,
806+ "timestamp" : "2025-01-15T10:30:00+00:00" ,
807+ "certificate" : "cert" ,
808+ "proficiency-levels" : {
809+ "beginner" : {
810+ "description" : "Beginner level" ,
811+ "pretopics" : [],
812+ },
813+ "advanced" : {
814+ "description" : "Advanced level" ,
815+ "pretopics" : [],
816+ },
817+ },
818+ "dependencies" : {
819+ "math" : "example.com/math-topics@1.0.0" ,
820+ },
821+ }
822+ )
823+
824+ # Act
825+ level_list = ProficiencyLevelList .from_json (json_str )
826+
827+ # Assert
828+ assert len (level_list .levels ) == 2
829+ assert "beginner" in level_list .levels
830+ assert "advanced" in level_list .levels
831+ assert level_list .levels ["beginner" ].description == "Beginner level"
832+
833+ assert "math" in level_list .dependencies
834+ assert level_list .dependencies ["math" ].owner == "example.com"
835+ assert level_list .dependencies ["math" ].name == "math-topics"
836+ assert level_list .dependencies ["math" ].version == "1.0.0"
837+
838+ def test_from_json_invalid_input (self ):
839+ """Test that non-JSON input raises error."""
840+
841+ # Arrange
842+ json_str = "not a json string"
843+
844+ # Act
845+ result = None
846+ try :
847+ ProficiencyLevelList .from_json (json_data = json_str )
848+ except Exception as e :
849+ result = e
850+
851+ # Assert
852+ assert isinstance (result , json .JSONDecodeError )
853+
854+ # Methods - Round trip (to_dict -> from_dict)
855+ def test_round_trip_to_dict_from_dict (self ):
856+ """Test converting to dict and back preserves data."""
857+
858+ # Arrange
859+ topic_list = TopicList (
860+ owner = "example.com" ,
861+ name = "math-topics" ,
862+ version = "1.0.0" ,
863+ timestamp = "2025-01-15T10:30:00+00:00" ,
864+ certificate = "cert" ,
865+ )
866+ topic_list .add_topic (Topic (id = "addition" ))
867+ topic_list .add_topic (Topic (id = "subtraction" ))
868+
869+ level_list = ProficiencyLevelList (
870+ owner = "example.com" ,
871+ name = "levels" ,
872+ description = "Math proficiency levels" ,
873+ version = "1.0.0" ,
874+ timestamp = "2025-01-15T10:30:00+00:00" ,
875+ certificate = "https://example.com/cert.pem" ,
876+ levels = {
877+ "beginner" : ProficiencyLevel (
878+ id = "beginner" ,
879+ description = "Beginner level" ,
880+ pretopics = {
881+ "math.addition" ,
882+ },
883+ ),
884+ "intermediate" : ProficiencyLevel (
885+ id = "intermediate" ,
886+ description = "Intermediate level" ,
887+ pretopics = {
888+ "math.subtraction" ,
889+ },
890+ ),
891+ },
892+ dependencies = {
893+ "math" : topic_list ,
894+ },
895+ )
896+
897+ # Act
898+ data = level_list .to_dict ()
899+ result = ProficiencyLevelList .from_dict (data )
900+
901+ # Assert
902+ assert result .owner == level_list .owner
903+ assert result .name == level_list .name
904+ assert result .description == level_list .description
905+ assert result .version == level_list .version
906+ assert result .timestamp == level_list .timestamp
907+ assert result .certificate == level_list .certificate
908+
909+ assert len (result .dependencies ) == 1
910+ assert "math" in result .dependencies
911+ assert result .dependencies ["math" ].full_name == topic_list .full_name
912+
913+ assert len (result .levels ) == 2
914+ assert result .levels ["beginner" ].description == "Beginner level"
915+ assert "math.addition" in result .levels ["beginner" ].pretopics
916+ assert result .levels ["intermediate" ].description == "Intermediate level"
917+ assert "math.subtraction" in result .levels ["intermediate" ].pretopics
918+
919+ def test_round_trip_to_json_from_json (self ):
920+ """Test converting to JSON and back preserves data."""
921+
922+ # Arrange
923+ topic_list = TopicList (
924+ owner = "example.com" ,
925+ name = "math-topics" ,
926+ version = "1.0.0" ,
927+ timestamp = "2025-01-15T10:30:00+00:00" ,
928+ certificate = "cert" ,
929+ )
930+ topic_list .add_topic (Topic (id = "addition" ))
931+ topic_list .add_topic (Topic (id = "subtraction" ))
932+
933+ level_list = ProficiencyLevelList (
934+ owner = "example.com" ,
935+ name = "levels" ,
936+ description = "Math proficiency levels" ,
937+ version = "1.0.0" ,
938+ timestamp = "2025-01-15T10:30:00+00:00" ,
939+ certificate = "https://example.com/cert.pem" ,
940+ dependencies = {
941+ "math" : topic_list ,
942+ },
943+ )
944+ level_list .add_level (
945+ ProficiencyLevel (
946+ id = "beginner" ,
947+ description = "Beginner level" ,
948+ pretopics = {
949+ "math.addition" ,
950+ },
951+ )
952+ )
953+ level_list .add_level (
954+ ProficiencyLevel (
955+ id = "intermediate" ,
956+ description = "Intermediate level" ,
957+ pretopics = {
958+ "math.subtraction" ,
959+ },
960+ )
961+ )
962+
963+ # Act
964+ json_str = level_list .to_json ()
965+ result = ProficiencyLevelList .from_json (json_str )
966+ round_trip_json = result .to_json ()
967+
968+ # Assert
969+ data = json .loads (json_str )
970+ round_trip_data = json .loads (round_trip_json )
971+ assert round_trip_data == data
706972
707973 # Debugging
708974 def test_repr (self ):
0 commit comments