def test_invalid():
    with pytest.raises(Exception):
        test_data = io.StringIO("""
            name: foo
            type: major
            degree: B.A.

            result:
                count: 1
                of:
                    - requirement: Foo

            requirements:
                - name: Foo
                  result:
                    count: 2
                    of:
                        - CSCI 121
                        - CSCI 125
                        - requirement: FooBar
        """)

        AreaOfStudy.load(specification=yaml.load(stream=test_data,
                                                 Loader=yaml.SafeLoader),
                         c=c)
def test_load():
    test_data = io.StringIO("""
        name: foo
        type: major
        degree: B.A.

        result:
          all:
            - requirement: Foo

        requirements:
          Foo:
            result:
              count: 2
              of:
                - course: CSCI 121
                - course: CSCI 125
                - requirement: FooBar
            requirements:
              FooBar:
                result:
                  both:
                    - course: CSCI 121
                    - course: CSCI 251
    """)

    AreaOfStudy.load(specification=yaml.load(stream=test_data,
                                             Loader=yaml.SafeLoader),
                     c=c)
def test_limit__at_most_1_credit():
    test_data = io.StringIO("""
        limit:
          - at_most: 1 credit
            where: {number: {$eq: 201}}

        result:
          from: courses
          assert: {count(courses): {$gte: 1}}
    """)

    area = AreaOfStudy.load(specification=yaml.load(stream=test_data, Loader=yaml.SafeLoader), c=c)

    course_1 = course_from_str("ABC 201", credits='0.5')
    course_2 = course_from_str("BCD 201", credits='0.5')
    course_3 = course_from_str("CDE 201", credits='0.5')
    transcript = [course_1, course_2, course_3]

    solutions = list(area.solutions(student=Student.load(dict(courses=transcript)), exceptions=[]))
    course_sets = set(frozenset(s.solution.output) for s in solutions)

    for i, s in enumerate(course_sets):
        print(i)
        for _c in s:
            print(_c.course())

    assert course_sets == set([
        frozenset((course_1, course_2)),
        frozenset((course_1, course_3)),
        frozenset((course_2, course_3)),
        frozenset((course_1,)),
        frozenset((course_2,)),
        frozenset((course_3,)),
        frozenset(()),
    ])
Exemple #4
0
def test_insertion_on_course_rule(caplog):
    caplog.set_level(logging.DEBUG)

    exception = load_exception({
        "type": "insert",
        "path": ["$", "*DEPT 345"],
        "clbid": "1",
    })

    course_a = course_from_str("OTHER 123", clbid="0")
    course_b = course_from_str("OTHER 234", clbid="1")
    transcript = [course_a, course_b]

    area = AreaOfStudy.load(specification={"result": {
        "course": "DEPT 345"
    }},
                            c=c,
                            student=Student.load(dict(courses=transcript)),
                            exceptions=[exception])
    solutions = list(
        area.solutions(student=Student.load(dict(courses=transcript)),
                       exceptions=[exception]))
    assert len(solutions) == 1

    result = solutions[0].audit()

    assert result.ok() is True
    assert result.was_overridden() is True
    assert result.claims()[0].claim.course.clbid == course_b.clbid
Exemple #5
0
def test_override_on_count_rule(caplog):
    caplog.set_level(logging.DEBUG)

    exception = load_exception({
        "type": "override",
        "path": ["$", ".count"],
        "status": "pass",
    })

    area = AreaOfStudy.load(specification={
        "result": {
            "any": [
                {
                    "course": "DEPT 123"
                },
            ],
        },
    },
                            c=c,
                            student=Student.load({}),
                            exceptions=[exception])
    solutions = list(
        area.solutions(student=Student.load({}), exceptions=[exception]))
    assert len(solutions) == 1

    result = solutions[0].audit()

    assert result.ok() is True
    assert result.was_overridden() is True
Exemple #6
0
def test_override_on_query_rule_audit_clause(caplog):
    caplog.set_level(logging.DEBUG)

    exception = load_exception({
        "type":
        "override",
        "path": ['$', '.query', '.assertions', '[0]', '.assert'],
        "status":
        "pass",
    })

    area = AreaOfStudy.load(specification={
        "result": {
            "from": "courses",
            "all": [{
                "assert": {
                    "count(courses)": {
                        "$gte": 1
                    }
                }
            }],
        },
    },
                            c=c,
                            exceptions=[exception])
    solutions = list(
        area.solutions(student=Student.load({}), exceptions=[exception]))
    assert len(solutions) == 1

    result = solutions[0].audit()

    assert result.result.resolved_assertions[0].was_overridden() is True
    assert result.ok() is True
    assert result.was_overridden() is False
Exemple #7
0
def test_from(caplog):
    caplog.set_level(logging.DEBUG)

    test_data = io.StringIO("""
        result:
            from: courses
            where: {gereqs: {$eq: SPM}}
            assert: {count(courses): {$gte: 1}}
    """)

    area = AreaOfStudy.load(specification=yaml.load(stream=test_data,
                                                    Loader=yaml.SafeLoader),
                            c=c)

    transcript = [
        course_from_str("CSCI 111", gereqs=['SPM'], year=2008, term='1'),
        course_from_str("ASIAN 110"),
    ]

    s = next(
        area.solutions(student=Student.load(dict(courses=transcript)),
                       exceptions=[]))
    a = s.audit().result

    assert len(a.successful_claims) == 1

    assert a.successful_claims[0].course.clbid == transcript[0].clbid
def test_limit__at_most_1_course():
    test_data = io.StringIO("""
        limit:
          - at_most: 1
            where: {number: {$eq: 201}}

        result:
          from: courses
          where: {number: {$eq: 201}}
          assert: {count(courses): {$gte: 1}}
    """)

    area = AreaOfStudy.load(specification=yaml.load(stream=test_data, Loader=yaml.SafeLoader), c=c)

    course_1 = course_from_str("BIO 201")
    course_2 = course_from_str("ABC 201")
    transcript = [course_1, course_2]

    solutions = list(area.solutions(student=Student.load(dict(courses=transcript)), exceptions=[]))
    course_sets = set(frozenset(s.solution.output) for s in solutions)

    assert course_sets == set([
        frozenset((course_2,)),
        frozenset((course_1,)),
        frozenset(()),
    ])
Exemple #9
0
def test_override_on_requirement_rule(caplog):
    caplog.set_level(logging.DEBUG)

    exception = load_exception({
        "type": "override",
        "path": ["$", r"%req"],
        "status": "pass",
    })

    area = AreaOfStudy.load(specification={
        "result": {
            "requirement": "req"
        },
        "requirements": {
            "req": {
                "department_audited": True
            },
        },
    },
                            c=c,
                            student=Student.load({}),
                            exceptions=[exception])
    solutions = list(
        area.solutions(student=Student.load({}), exceptions=[exception]))
    assert len(solutions) == 1

    result = solutions[0].audit()

    assert result.ok() is True
    assert result.was_overridden() is True
Exemple #10
0
def test_limits_esth(caplog):
    spec = """
    result:
      from: courses
      limit:
        - at_most: 1
          where:
            $or:
              - course: {$in: ['STAT 110', 'STAT 212', 'STAT 214']}
              - ap: {$eq: AP Statistics}
      assert: {count(courses): {$gte: 2}}
    """

    area = AreaOfStudy.load(specification=yaml.load(stream=spec,
                                                    Loader=yaml.SafeLoader),
                            c=c)

    psych_241 = course_from_str("PSYCH 241", clbid="0")
    stat_212 = course_from_str("STAT 212", clbid="1")
    ap_stat = course_from_str("STAT 0",
                              name="AP Statistics",
                              course_type="AP",
                              clbid="2")
    transcript = [psych_241, stat_212, ap_stat]

    solutions = list(
        area.solutions(student=Student.load(dict(courses=transcript)),
                       exceptions=[]))
    course_sets = [list(s.solution.output) for s in solutions]

    assert course_sets == [
        [psych_241],
        [psych_241, stat_212],
        [psych_241, ap_stat],
    ]
Exemple #11
0
def test_multi_insertion_on_query_rule_audit_clause(caplog):
    caplog.set_level(logging.DEBUG)

    exception = load_exception({
        "type":
        "insert",
        "path": ['$', '.query', '.assertions', '[0]', '.assert'],
        "clbid":
        "1",
    })
    exception2 = load_exception({
        "type":
        "insert",
        "path": ['$', '.query', '.assertions', '[0]', '.assert'],
        "clbid":
        "2",
    })

    course_a = course_from_str("DEPT 123", clbid="0")
    course_b = course_from_str("DEPT 345", clbid="1")
    course_c = course_from_str("DEPT 234", clbid="2")
    transcript = [course_a, course_b, course_c]

    area = AreaOfStudy.load(specification={
        "result": {
            "from": "courses",
            "all": [{
                "assert": {
                    "count(courses)": {
                        "$gte": 1
                    }
                }
            }],
        },
    },
                            c=c,
                            student=Student.load(dict(courses=transcript)),
                            exceptions=[exception, exception2])
    solutions = list(
        area.solutions(student=Student.load(dict(courses=transcript)),
                       exceptions=[exception, exception2]))
    assert len(solutions) == 7

    result = solutions[0].audit()

    assert result.result.resolved_assertions[0].was_overridden() is False

    assert result.ok() is True
    assert result.was_overridden() is False

    assert result.result.resolved_assertions[0].was_overridden() is False
    assert set(
        result.result.resolved_assertions[0].assertion.resolved_items) == set(
            ['1', '0', '2'])

    assert result.claims()[0].claim.course.clbid == course_a.clbid
    assert len(result.claims()) == 1
Exemple #12
0
def __get_data(spec):
    area = AreaOfStudy.load(specification=yaml.load(stream=io.StringIO(spec), Loader=yaml.SafeLoader), c=c)

    transcript = [
        course_from_str("CSCI 113", gereqs=['SPM'], term=20071),
        course_from_str("CSCI 112", gereqs=['SPM'], term=20081),
        course_from_str("CSCI 111", gereqs=['SPM'], term=20091),
    ]

    return (area, transcript)
Exemple #13
0
def test_global_limits(caplog):
    caplog.set_level(logging.DEBUG)

    test_data = io.StringIO("""
        limit:
          - at_most: 1
            where: {level: {$eq: 200}}
          - at_most: 1
            where: {level: {$eq: 300}}

        result:
          from: courses
          where: {subject: {$eq: BIO}}
          assert: {count(courses): {$gte: 1}}
    """)

    area = AreaOfStudy.load(specification=yaml.load(stream=test_data,
                                                    Loader=yaml.SafeLoader),
                            c=c)

    bio_101 = course_from_str("BIO 101")
    bio_201 = course_from_str("BIO 201")
    bio_202 = course_from_str("BIO 202")
    bio_301 = course_from_str("BIO 301")
    bio_302 = course_from_str("BIO 302")
    transcript = [bio_101, bio_201, bio_202, bio_301, bio_302]

    solutions = list(
        area.solutions(student=Student.load(dict(courses=transcript)),
                       exceptions=[]))
    course_sets = set([frozenset(s.solution.output) for s in solutions])

    assert course_sets == set([
        frozenset((bio_101, bio_201)),
        frozenset((bio_101, bio_201, bio_301)),
        frozenset((bio_101, bio_201, bio_302)),
        frozenset((bio_101, bio_202)),
        frozenset((bio_101, bio_202, bio_301)),
        frozenset((bio_101, bio_202, bio_301)),
        frozenset((bio_101, bio_202, bio_302)),
        frozenset((bio_101, bio_301)),
        frozenset((bio_101, bio_302)),
        frozenset((bio_101, )),
        frozenset((bio_201, bio_301)),
        frozenset((bio_201, bio_302)),
        frozenset((bio_201, )),
        frozenset((bio_202, bio_301)),
        frozenset((bio_202, bio_302)),
        frozenset((bio_202, )),
        frozenset((bio_301, )),
        frozenset((bio_302, )),
    ])
Exemple #14
0
def test_multi_insertion_on_count_rule__any_with_natural(caplog):
    caplog.set_level(logging.DEBUG)

    exception = load_exception({
        "type": "insert",
        "path": ['$', '.count'],
        "clbid": "1",
    })
    exception2 = load_exception({
        "type": "insert",
        "path": ['$', '.count'],
        "clbid": "2",
    })

    course_a = course_from_str("DEPT 123", clbid="0")
    course_b = course_from_str("OTHER 234", clbid="1")
    course_c = course_from_str("OTHER 222", clbid="2")
    transcript = [course_a, course_b, course_c]

    area = AreaOfStudy.load(specification={
        "result": {
            "any": [
                {
                    "course": "DEPT 123"
                },
            ],
        },
    },
                            c=c,
                            student=Student.load(dict(courses=transcript)),
                            exceptions=[exception, exception2])
    solutions = list(
        area.solutions(student=Student.load(dict(courses=transcript)),
                       exceptions=[exception, exception2]))
    print([s.solution for s in solutions])

    assert [[
        x.course for x in s.solution.items if isinstance(x, CourseResult)
    ] for s in solutions] == [['DEPT 123', 'OTHER 234', 'OTHER 222']]
    assert len(solutions) == 1

    result = solutions[0].audit()

    assert result.result.count == 1
    assert result.ok() is True
    assert result.was_overridden() is False
    assert result.claims()[0].claim.course.clbid == course_a.clbid
    assert result.claims()[1].claim.course.clbid == course_b.clbid
    assert result.claims()[2].claim.course.clbid == course_c.clbid
Exemple #15
0
def test_multi_insertion_on_query_rule(caplog):
    caplog.set_level(logging.DEBUG)

    exception = load_exception({
        "type": "insert",
        "path": ["$", ".query"],
        "clbid": "0",
    })
    exception2 = load_exception({
        "type": "insert",
        "path": ["$", ".query"],
        "clbid": "1",
    })

    course_a = course_from_str("OTHER 123", clbid="0")
    course_b = course_from_str("OTHER 111", clbid="1")
    transcript = [course_a, course_b]

    area = AreaOfStudy.load(specification={
        "result": {
            "from": "courses",
            "where": {
                "subject": {
                    "$eq": "ABC"
                }
            },
            "assert": {
                "count(courses)": {
                    "$gte": 1
                }
            },
        },
    },
                            c=c,
                            student=Student.load(dict(courses=transcript)),
                            exceptions=[exception, exception2])
    solutions = list(
        area.solutions(student=Student.load(dict(courses=transcript)),
                       exceptions=[exception, exception2]))
    assert len(solutions) == 3

    result = solutions[0].audit()

    assert result.ok() is True
    assert result.was_overridden() is False
    assert result.claims()[0].claim.course.clbid == course_a.clbid
    assert len(result.claims()) == 1
Exemple #16
0
def test_mc__none_2(caplog):
    caplog.set_level(logging.DEBUG, logger='dp.context')

    test_data = io.StringIO("""
        result:
            either:
                - requirement: Root
                - requirement: Alt

        requirements:
            Root:
                result:
                    course: DEPT 123

            Alt:
                result:
                    course: DEPT 123

        multicountable:
            DEPT 123:
                - [Root]
    """)

    area = AreaOfStudy.load(specification=yaml.load(stream=test_data,
                                                    Loader=yaml.SafeLoader),
                            c=c)

    course = course_from_str('DEPT 123')

    solutions = area.solutions(student=Student.load(dict(courses=[course])),
                               exceptions=[])

    results = [s.audit() for s in solutions]
    assert len(results) == 3

    result_a, result_b, result_c = results
    assert result_a.is_ok() is True
    assert result_b.is_ok() is True
    assert result_c.is_ok() is True

    assert list(c.course.course() for c in result_c.claims()
                if c.failed is False) == [course.course()]

    assert result_c.result.items[0].result.claim_attempt.failed is False
    assert result_c.result.items[1].result.claim_attempt.failed is True
Exemple #17
0
def test_mc__only_query_references(caplog):
    caplog.set_level(logging.DEBUG, logger='dp.context')

    test_data = io.StringIO("""
        result:
            all:
                - requirement: Root
                - requirement: Alt

        requirements:
            Root:
                result:
                    from: courses
                    assert: {count(courses): {$gte: 1}}

            Alt:
                result:
                    from: courses
                    assert: {count(courses): {$gte: 1}}

        multicountable:
            DEPT 123:
                - [Root]
                - [Alt]
    """)

    area = AreaOfStudy.load(specification=yaml.load(stream=test_data,
                                                    Loader=yaml.SafeLoader),
                            c=c)

    course = course_from_str('DEPT 123')

    solutions = area.solutions(student=Student.load(dict(courses=[course])),
                               exceptions=[])

    results = [s.audit() for s in solutions]
    assert len(results) == 1

    result_a = results[0]
    assert result_a.is_ok() is True

    assert list(c.course.course() for c in result_a.claims()
                if c.failed is False) == [course.course(),
                                          course.course()]
Exemple #18
0
def test_overlaps(caplog: Any) -> None:
    # caplog.set_level(logging.DEBUG)
    global c

    area = AreaOfStudy.load(c=c, specification={
        "result": {"all": [
            {"requirement": "Core"},
            {"requirement": "Electives"},
        ]},
        "requirements": {
            "Core": {
                "result": {"all": [
                    {"course": "MUSIC 212"},
                    {"course": "MUSIC 214"},
                ]},
            },
            "Electives": {
                "result": {
                    "from": "courses",
                    "where": {
                        "$and": [
                            {"subject": {"$eq": "MUSIC"}},
                            {"level": {"$eq": [300]}},
                        ],
                    },
                    "all": [
                        {"assert": {"count(courses)": {"$gte": 2}}},
                    ],
                },
            },
        },
    })

    transcript = [course_from_str(c) for c in ["MUSIC 212", "MUSIC 214", "MUSIC 301", "MUSIC 302"]]
    ctx = RequirementContext().with_transcript(transcript)

    area.result.find_independent_children(items=area.result.items, ctx=ctx)

    solutions = list(area.solutions(student=Student.load(dict(courses=transcript)), exceptions=[]))
    assert len(solutions) == 1

    result = solutions[0].audit()

    assert result.ok() is True
Exemple #19
0
def test_override_on_count_rule_assertion_clause(caplog):
    caplog.set_level(logging.DEBUG)

    exception = load_exception({
        "type":
        "override",
        "path": ['$', '.count', '.audit', '[0]', '.assert'],
        "status":
        "pass",
    })

    course_a = course_from_str("DEPT 234", clbid="0")
    course_b = course_from_str("DEPT 345", clbid="1")
    transcript = [course_a, course_b]

    area = AreaOfStudy.load(specification={
        "result": {
            "all": [{
                "course": "DEPT 123"
            }],
            "audit": {
                "assert": {
                    "count(courses)": {
                        "$gte": 1
                    }
                }
            },
        },
    },
                            c=c,
                            student=Student.load(dict(courses=transcript)),
                            exceptions=[exception])
    solutions = list(
        area.solutions(student=Student.load(dict(courses=transcript)),
                       exceptions=[exception]))
    assert len(solutions) == 1

    result = solutions[0].audit()

    assert result.result.audits()[0].was_overridden() is True
    assert result.ok() is False
    assert result.was_overridden() is False
Exemple #20
0
def test_insertion_on_requirement_rule(caplog):
    '''the long and short of this test is, attempting to insert a course
    directly into a Requirement directly should do nothing.'''

    caplog.set_level(logging.DEBUG)

    exception = load_exception({
        "type": "insert",
        "path": ["$", r"%req"],
        "clbid": "2",
    })

    print('start')

    area = AreaOfStudy.load(specification={
        "result": {
            "requirement": "req"
        },
        "requirements": {
            "req": {
                "result": {
                    "course": "DEPT 123"
                }
            },
        },
    },
                            c=c,
                            student=Student.load({}),
                            exceptions=[exception])
    solutions = list(
        area.solutions(student=Student.load({}), exceptions=[exception]))
    assert len(solutions) == 1

    print('begin audit')

    result = solutions[0].audit()

    print(result)

    assert result.ok() is False
    assert result.was_overridden() is False
Exemple #21
0
def test_pruning_on_count_rule(caplog):
    caplog.set_level(logging.DEBUG)

    area = AreaOfStudy.load(specification={
        "result": {
            "any": [
                {
                    "course": "DEPT 123"
                },
                {
                    "course": "DEPT 234"
                },
                {
                    "course": "DEPT 345"
                },
            ],
        },
    },
                            c=c)

    course_a = course_from_str("DEPT 123", clbid="0")
    course_b = course_from_str("DEPT 234", clbid="1")
    transcript = [course_a, course_b]

    solutions = list(
        area.solutions(student=Student.load(dict(courses=transcript)),
                       exceptions=[]))

    assert [[
        x.course for x in s.solution.items if isinstance(x, CourseResult)
    ] for s in solutions] == [['DEPT 123', 'DEPT 234']]
    assert len(solutions) == 1

    result = solutions[0].audit()

    assert result.result.count == 1
    assert result.ok() is True
    assert result.was_overridden() is False
    assert result.claims()[0].claim.course.clbid == course_a.clbid
Exemple #22
0
def test_insertion_on_count_rule__all(caplog):
    caplog.set_level(logging.DEBUG)

    exception = load_exception({
        "type": "insert",
        "path": ['$', '.count'],
        "clbid": "2",
    })

    course_a = course_from_str("DEPT 123", clbid="0")
    course_b = course_from_str("DEPT 234", clbid="1")
    course_c = course_from_str("DEPT 345", clbid="2")
    transcript = [course_a, course_b, course_c]

    area = AreaOfStudy.load(specification={
        "result": {
            "all": [
                {
                    "course": "DEPT 123"
                },
                {
                    "course": "DEPT 234"
                },
            ],
        },
    },
                            c=c,
                            student=Student.load(dict(courses=transcript)),
                            exceptions=[exception])
    solutions = list(
        area.solutions(student=Student.load(dict(courses=transcript)),
                       exceptions=[exception]))
    assert len(solutions) == 1

    result = solutions[0].audit()

    assert result.result.count == 3
    assert result.ok() is True
    assert result.was_overridden() is False
Exemple #23
0
def x_test_overlaps(caplog: Any) -> None:
    # caplog.set_level(logging.DEBUG)

    area = AreaOfStudy.load(c=c, specification={
        "result": {"all": [
            {"requirement": "Core"},
            {"requirement": "Electives"},
            {"requirement": "Lessons"},
        ]},
        "requirements": {
            "Core": {
                "result": {"all": [
                    {"course": "MUSIC 212"},
                    {"course": "MUSIC 214"},
                    {"course": "MUSIC 237"},
                    {"course": "MUSIC 251"},
                    {"course": "MUSIC 261"},
                    {"course": "MUSIC 298"},
                ]},
            },
            "Electives": {
                "result": {
                    "from": "courses",
                    "where": {
                        "$and": [
                            {"subject": {"$eq": "MUSIC"}},
                            {"level": {"$in": [200, 300]}},
                        ],
                    },
                    "all": [
                        {"assert": {"count(courses)": {"$gte": 8}}},
                        {
                            "where": {"level": {"$eq": 300}},
                            "assert": {"count(courses)": {"$gte": 2}},
                        },
                    ],
                },
            },
            "Lessons": {
                "result": {
                    "from": "courses",
                    "where": {"subject": {"$eq": "MUSPF"}},
                    "all": [
                        {"assert": {"count(terms)": {"$gte": 6}}},
                        {"assert": {"sum(credits)": {"$gte": 2.5}}},
                        {
                            "where": {"credits": {"$eq": 0.5}},
                            "assert": {"count(terms)": {"$gte": 4}},
                        },
                    ],
                },
            },
        },
    })

    transcript = [course_from_str(c) for c in [
        "MUSIC 212", "MUSIC 214", "MUSIC 237", "MUSIC 251", "MUSIC 252", "MUSIC 298",
        "MUSIC 222", "MUSIC 224", "MUSIC 247", "MUSIC 261", "MUSIC 262", "MUSIC 299", "MUSIC 301", "MUSIC 302",
        "MUSPF 101", "MUSPF 102", "MUSPF 103", "MUSPF 104", "MUSPF 105", "MUSPF 106",
    ]]

    solutions = list(area.solutions(student=Student.load(dict(courses=transcript)), exceptions=[]))
    assert len(solutions) == 1

    result = solutions[0].audit()

    assert result.ok() is True