module TestGeneration; from Test_Preferences import all; from QuestionManagement import all; from TestPackage import all; export all; object TestFilter is components: tn:TestName and class:Class and ft:FilterTime and fl:FilterLength and td:TestDifficulty and useOld:IsReuse and numDays:DaysOld and author:Author* and rand:IsRandom and tkw:TestKeyword* and ntf:NumTF and nmc:NumMC and ness:NumEssay and ncde:NumCode and nfill:NumFill; description: (*Specefies the parameters for which questions in QuestionDatabase must adhere to. *); end TestFilter; object FilterTime is components: integer; description: (* The user-inputted duration of a test. *); end FilterTime; object FilterLength is components: integer; description: (* The user-inputted number of questions of a test. *); end FilterLength; object IsReuse is components: boolean; description: (* Determines whether the user wants to enable the filter by days option for question filtering from a question database. *); end IsReuse; object DaysOld is components: integer; description: (* The user-inputted value that uses questions whose LastUsed component is more than DaysOld away. IsReuse must be true for this option to be enabled. *); end DaysOld; object IsRandom is components: boolean; description: (* Determines whether the user wants to specify the number of each question format or not. *); end IsRandom; object NumTF is components: integer; description: (* Allows the user to specify how many true/false questions should be on a test. IsRandom must be false for this object to be valid. *); end NumTF; object NumMC is components: integer; description: (* Allows the user to specify how many multiple choice questions should be on a test. IsRandom must be false for this object to be valid. *); end NumMC; object NumEssay is components: integer; description: (* Allows the user to specify how many essay questions should be on a test. IsRandom must be false for this object to be valid. *); end NumEssay; object NumCode is components: integer; description: (* Allows the user to specify how many coding questions should be on a test. IsRandom must be false for this object to be valid. *); end NumCode; object NumFill is components: integer; description: (* Allows the user to specify how many fill in the blank questions should be on a test. IsRandom must be false for this object to be valid. *); end NumFill; object SystemTime is components: t:integer; description: (* The current system time. *); end SystemTime; function Today(st:SystemTime) = (* Today's date in an integer form. *) st.t; operation CreateTest inputs: tst:Test, tf:TestFilter, qdb:QuestionDatabase, tp:TestPreferences, st:SystemTime; outputs: tst':Test; precondition: (* * The test is blank. *) #tst.qs = 0 and (* * The TestName field has a value. *) tf.tn != nil and (* * The Class field has a value. *) exists (q in qdb.qs) q.class = tf.class and (* * The FilterTime field has a valid value defined * as more than 0 and less than 24 hours. *) (tf.ft != nil) and (tf.ft > 0) and (tf.ft <= 1440) and (* * The Difficulty field has a valud value between * 1 and 10. *) (tf.td >= 1) and (tf.td <= 10) and (* * IsReuse is true iff DaysOld has a valid value *) tf.useOld iff (tf.numDays > 0) and (* * Question format is defined by the user iff * all question format counts have valid values, and * all values add to total number of questions, if * number of questions is defined by the user. *) tf.rand iff (tf.ntf >= 0) and (tf.nmc >= 0) and (tf.ness >= 0) and (tf.ncde >= 0) and (tf.nfill >= 0) and (if (tf.fl != nil) then (tf.ntf + tf.nmc + tf.ness + tf.ncde + tf.nfill = tf.fl)); postcondition: (* * All questions in tst' were pulled from qdb. *) forall (q:TestQuestion) (q in tst'.qs) iff (q in qdb.qs) and (* * All questions in tst' satisfy the TestFilter * conditions. *) forall (q:TestQuestion) (if (q in tst'.qs) then ((q.class = tf.class) and ((q.diff + tp.df.v >= tf.td) or (q.diff - tp.df.v <= tf.td)) and (if (tf.useOld) then (q.lu + tf.numDays < Today(st))) and forall (j:integer | j >= 1 and j <= #q.keywords) (q.keywords[j] in tf.tkw)) and (* * The outputted test satisfies the TestFilter * conditions. *) (tst'.tn = tf.tn) and (tst'.cl = tf.class) and ((tst'.tl + tp.tv.v >= tf.ft) or (tst'.tl - tp.tv.v <= tf.ft)) and ((#tst'.qs + tp.tlv.v >= tf.fl) or (#tst'.qs - tp.tlv.v <= tf.fl)) and ((tst'.td + tp.df.v >= tf.td) or (tst'.td - tp.df.v <= tf.td)) and (tst'.tkw = tf.tkw) and ((tst'.ntf + tp.fv.v >= tf.ntf) or (tst'.ntf - tp.fv.v <= tf.ntf)) and ((tst'.nmc + tp.fv.v >= tf.nmc) or (tst'.nmc - tp.fv.v <= tf.nmc)) and ((tst'.ness + tp.fv.v >= tf.ness) or (tst'.ness - tp.fv.v <= tf.ness)) and ((tst'.ncde + tp.fv.v >= tf.ncde) or (tst'.ncde - tp.fv.v <= tf.ncde)) and ((tst'.nfill + tp.fv.v >= tf.nfill) or (tst'.nfill - tp.fv.v <= tf.nfill))); description: (* Creates a new test using TestFilter to sort out questions in the QuestionDatabase *); end CreateTest; end TestGeneration;