)>}]
شركة التطبيقات المتكاملة لتصميم وبرمجة البرمجيات الخاصة ش.ش.و.
Integrated Applications Programming Company
Skip Navigation LinksHome » Code Library » Test

Public general use code classes and xml files that we've compiled and used over the years:

Test Class

    1: using System;
    2: using System.Linq;
    3: using System.Data;
    4: using System.Collections.Generic;
    5: using Microsoft.EntityFrameworkCore;
    6:  
    7: namespace Ia.TentPlay.Cl.Model.Memorise
    8: {
    9:     ////////////////////////////////////////////////////////////////////////////
   10:  
   11:     /// <summary publish="true">
   12:     /// Test Class
   13:     /// </summary>
   14:     /// <value>
   15:     /// https://msdn.microsoft.com/en-us/library/z1hkazw7(v=vs.100).aspx
   16:     /// </value>
   17:     /// <remarks> 
   18:     /// Copyright © 2008-2018 Jasem Y. Al-Shamlan (info@ia.com.kw), Integrated Applications - Kuwait. All Rights Reserved.
   19:     ///
   20:     /// This library is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by
   21:     /// the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
   22:     ///
   23:     /// This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
   24:     /// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   25:     /// 
   26:     /// You should have received a copy of the GNU General Public License along with this library. If not, see http://www.gnu.org/licenses.
   27:     /// 
   28:     /// Copyright notice: This notice may not be removed or altered from any source distribution.
   29:     /// </remarks> 
   30:     public abstract class Test
   31:     {
   32:         protected static Random random = new Random(DateTime.UtcNow.Second);
   33:  
   34:         protected static int NumberOfMinutesThatMustPassBeforeAWordIsTestedAgain = 3;
   35:  
   36:         protected static TimeSpan ResponseSecondsThatIndicateMemorizationTimeSpan
   37:         {
   38:             get
   39:             {
   40:                 return TimeSpan.Parse("00:00:03"); // three seconds indicate memorization
   41:             }
   42:         }
   43:  
   44:         //static int numberOfCumulativeAnswerCorrectnessIndicatorThatIndicatesRetention = 7;
   45:         //static int numberOfPoolWords = 7 * 7;
   46:         protected abstract TestTopic testTopic { get; }
   47:  
   48:         // below: order is very important
   49:         /// </summary>
   50:         public enum TestTopic { MorseCode = 0, German = 1, Math = 2, Kanji = 3, Russian = 4, Kana = 5, PhoneticAlphabet = 6 };
   51:  
   52:         /// </summary>
   53:         public enum TestOption { PrefereOrderByAscendingId, PreferRandom }
   54:  
   55:         /// </summary>
   56:         public enum AnswerType { Correct, CorrectButSlow, Incorrect }
   57:  
   58:         /*
   59:          * Calculate and return the proper words withing a proper question range based on the test taking history from the database
   60:          * 
   61:          * - Initially all words will have Enabled = false.
   62:          * - The process will assign a pool of enabled words for testing.
   63:          * - At any time the user will be memorizing the pool of words only.
   64:          * - If a word is consedered memorised by its test history it will exit the word testing pool and another will be randomly added
   65:          */
   66:  
   67:         ////////////////////////////////////////////////////////////////////////////
   68:  
   69:         /// <summary>
   70:         ///
   71:         /// </summary>
   72:         public Test() { }
   73:  
   74:         ////////////////////////////////////////////////////////////////////////////
   75:  
   76:         /// <summary>
   77:         ///
   78:         /// </summary>
   79:         public void CalculatedTestQuestionAndOptions(TestOption testOption, out Ia.TentPlay.Cl.Model.Memorise.Score testQuestion, out List<Ia.TentPlay.Cl.Model.Memorise.Score> optionList, out string debug)
   80:         {
   81:             int testQuestionTypeId, testQuestionId, optionIndex1, optionIndex2, optionIndex3;
   82:             DateTime timeMinusMinutesThatMustPassBeforeAWordIsTestedAgainDateTime;
   83:             List<Ia.TentPlay.Cl.Model.Memorise.Score> questionList;
   84:  
   85:             debug = "";
   86:             optionIndex1 = optionIndex2 = optionIndex3 = 0;
   87:             optionList = new List<Ia.TentPlay.Cl.Model.Memorise.Score>();
   88:  
   89:             timeMinusMinutesThatMustPassBeforeAWordIsTestedAgainDateTime = DateTime.UtcNow.AddHours(3).AddMinutes(-NumberOfMinutesThatMustPassBeforeAWordIsTestedAgain);
   90:  
   91:             testQuestionTypeId = WeightedRandomTypeIdAccordingTypeDistribution(Guid.Empty);
   92:  
   93:             using (var db = new Ia.TentPlay.Db())
   94:             {
   95:                 if (testOption == TestOption.PreferRandom || testOption == TestOption.PrefereOrderByAscendingId)
   96:                 {
   97:                     if (testOption == TestOption.PreferRandom)
   98:                     {
   99:                         testQuestion = (from s in db.Scores
  100:                                         where s.TestId == (int)testTopic && s.TypeId == testQuestionTypeId && s.Viewed < timeMinusMinutesThatMustPassBeforeAWordIsTestedAgainDateTime
  101:                                         orderby s.CumulativeAnswerCorrectnessIndicator, s.NumberOfTimesAsked, s.NumberOfConsecutiveCorrects, s.UserId ascending
  102:                                         select s).Take(5).FirstOrDefault();
  103:  
  104:                         if (testQuestion == null)
  105:                         {
  106:                             testQuestion = (from s in db.Scores
  107:                                             where s.TestId == (int)testTopic && s.TypeId == testQuestionTypeId
  108:                                             orderby s.CumulativeAnswerCorrectnessIndicator, s.NumberOfTimesAsked, s.NumberOfConsecutiveCorrects, s.UserId ascending
  109:                                             select s).Take(5).FirstOrDefault();
  110:                         }
  111:                     }
  112:                     else if (testOption == TestOption.PrefereOrderByAscendingId)
  113:                     {
  114:                         testQuestion = (from s in db.Scores
  115:                                         where s.TestId == (int)testTopic && s.TypeId == testQuestionTypeId && s.Viewed < timeMinusMinutesThatMustPassBeforeAWordIsTestedAgainDateTime
  116:                                         orderby s.CumulativeAnswerCorrectnessIndicator, s.NumberOfTimesAsked, s.NumberOfConsecutiveCorrects, s.Id, s.UserId ascending
  117:                                         select s).Take(5).FirstOrDefault();
  118:  
  119:                         if (testQuestion == null)
  120:                         {
  121:                             testQuestion = (from s in db.Scores
  122:                                             where s.TestId == (int)testTopic && s.TypeId == testQuestionTypeId
  123:                                             orderby s.CumulativeAnswerCorrectnessIndicator, s.NumberOfTimesAsked, s.NumberOfConsecutiveCorrects, s.Id, s.UserId ascending
  124:                                             select s).Take(5).FirstOrDefault();
  125:                         }
  126:                     }
  127:                     else
  128:                     {
  129:                         throw new Exception("Unrecognized test option");
  130:                     }
  131:  
  132:                     if (testQuestion != null)
  133:                     {
  134:                         testQuestionId = testQuestion.Id;
  135:                         testQuestionTypeId = testQuestion.TypeId;
  136:  
  137:                         // below: update Viewed
  138:                         testQuestion.Viewed = DateTime.UtcNow.AddHours(3);
  139:                         db.SaveChanges();
  140:  
  141:                         questionList = (from s in db.Scores where s.TestId == (int)testTopic && s.TypeId == testQuestionTypeId && s.Id != testQuestionId select s).ToList();
  142:  
  143:                         if (questionList.Count > 0)
  144:                         {
  145:                             // below: select random, non-similar numbers
  146:                             while (optionIndex1 == optionIndex2 || optionIndex1 == optionIndex3 || optionIndex2 == optionIndex3 || questionList[optionIndex1].Answer == testQuestion.Answer || questionList[optionIndex2].Answer == testQuestion.Answer || questionList[optionIndex3].Answer == testQuestion.Answer)
  147:                             {
  148:                                 optionIndex1 = random.Next(questionList.Count);
  149:                                 optionIndex2 = random.Next(questionList.Count);
  150:                                 optionIndex3 = random.Next(questionList.Count);
  151:                             }
  152:  
  153:                             optionList.Add(questionList[optionIndex1]);
  154:                             optionList.Add(questionList[optionIndex2]);
  155:                             optionList.Add(questionList[optionIndex3]);
  156:  
  157:                             // below: insert the correct answer randomally
  158:                             optionList.Insert(random.Next(optionList.Count + 1), testQuestion);
  159:                         }
  160:                         else
  161:                         {
  162:                             throw new Exception("questionList.Count == 0");
  163:                         }
  164:                     }
  165:                     else
  166:                     {
  167:                         throw new Exception("testQuestion == null");
  168:                     }
  169:                 }
  170:                 else
  171:                 {
  172:                     throw new Exception("Unrecognized test option");
  173:                 }
  174:             }
  175:         }
  176:  
  177:         ////////////////////////////////////////////////////////////////////////////
  178:  
  179:         /// <summary>
  180:         ///
  181:         /// </summary>
  182:         public Ia.TentPlay.Cl.Model.Memorise.Test.AnswerType CheckSelectedAnswerToQuestion(Ia.TentPlay.Cl.Model.Memorise.Score testQuestion, Ia.TentPlay.Cl.Model.Memorise.Score selectedOption, TimeSpan responseTimeSpan, out string debug)
  183:         {
  184:             Ia.TentPlay.Cl.Model.Memorise.Test.AnswerType answerType;
  185:  
  186:             using (var db = new Ia.TentPlay.Db())
  187:             {
  188:                 testQuestion = db.Scores.FirstOrDefault(q => q.Id == testQuestion.Id);
  189:  
  190:                 debug = "timeSpan: " + responseTimeSpan.TotalSeconds + "; cu: " + testQuestion.CumulativeAnswerCorrectnessIndicator + "; num ask: " + testQuestion.NumberOfTimesAsked + "; num con cu: " + testQuestion.NumberOfConsecutiveCorrects + "; av cu:" + string.Format("{0:0.00}", AverageCumulativeAnswerCorrectnessIndicator());
  191:  
  192:                 if (testQuestion.Answer == selectedOption.Answer)
  193:                 {
  194:                     if (responseTimeSpan < ResponseSecondsThatIndicateMemorizationTimeSpan)
  195:                     {
  196:                         testQuestion.CumulativeAnswerCorrectnessIndicator++;
  197:                         testQuestion.NumberOfConsecutiveCorrects++;
  198:  
  199:                         answerType = Ia.TentPlay.Cl.Model.Memorise.Test.AnswerType.Correct;
  200:                     }
  201:                     else
  202:                     {
  203:                         answerType = Ia.TentPlay.Cl.Model.Memorise.Test.AnswerType.CorrectButSlow;
  204:                     }
  205:                 }
  206:                 else
  207:                 {
  208:                     testQuestion.CumulativeAnswerCorrectnessIndicator--;
  209:                     testQuestion.NumberOfConsecutiveCorrects = 0;
  210:  
  211:                     answerType = Ia.TentPlay.Cl.Model.Memorise.Test.AnswerType.Incorrect;
  212:                 }
  213:  
  214:                 testQuestion.Updated = testQuestion.Viewed = DateTime.UtcNow.AddHours(3);
  215:                 testQuestion.NumberOfTimesAsked++;
  216:  
  217:                 db.SaveChanges();
  218:             }
  219:  
  220:             return answerType;
  221:         }
  222:  
  223:         ////////////////////////////////////////////////////////////////////////////
  224:  
  225:         /// <summary>
  226:         ///
  227:         /// </summary>
  228:         public double AverageCumulativeAnswerCorrectnessIndicator()
  229:         {
  230:             double average;
  231:  
  232:             average = 0;
  233:  
  234:             using (var db = new Ia.TentPlay.Db())
  235:             {
  236:                 average = (from s in db.Scores where s.TestId == (int)testTopic select s.CumulativeAnswerCorrectnessIndicator).Average();
  237:             }
  238:  
  239:             return average;
  240:         }
  241:  
  242:         ////////////////////////////////////////////////////////////////////////////
  243:  
  244:         /// <summary>
  245:         ///
  246:         /// </summary>
  247:         public abstract void PopulateTestDatabaseTableWithInitialQuestionsIfEmpty(Guid userId);
  248:  
  249:         ////////////////////////////////////////////////////////////////////////////
  250:  
  251:         /// <summary>
  252:         ///
  253:         /// </summary>
  254:         public abstract int WeightedRandomTypeIdAccordingTypeDistribution(Guid userId);
  255:  
  256:         ////////////////////////////////////////////////////////////////////////////
  257:  
  258:         /// <summary>
  259:         ///
  260:         /// </summary>
  261:         public void DeleteTestRecordsOfUser(Guid userId)
  262:         {
  263:             using (var db = new Ia.TentPlay.Db())
  264:             {
  265:                 db.Database.ExecuteSqlCommand("delete from Scores where userId = {0}", userId);
  266:             }
  267:         }
  268:  
  269:         ////////////////////////////////////////////////////////////////////////////
  270:         ////////////////////////////////////////////////////////////////////////////    
  271:     }
  272:  
  273:     ////////////////////////////////////////////////////////////////////////////
  274:     ////////////////////////////////////////////////////////////////////////////   
  275: }