Professional Applications Programmers/Consultants برمجة واستشارات تطبيقات الإنترنت
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 System.Data.Entity;
   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), Internet 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(null);
  92:   
  93:              using (var db = new Ia.TentPlay.Db.Memorise())
  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, Guid.NewGuid() 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, Guid.NewGuid() 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, Guid.NewGuid() 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, Guid.NewGuid() 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.Memorise())
 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.Memorise())
 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(string userId);
 248:   
 249:          ////////////////////////////////////////////////////////////////////////////
 250:   
 251:          /// <summary>
 252:          ///
 253:          /// </summary>
 254:          public abstract int WeightedRandomTypeIdAccordingTypeDistribution(string userId);
 255:   
 256:          ////////////////////////////////////////////////////////////////////////////
 257:   
 258:          /// <summary>
 259:          ///
 260:          /// </summary>
 261:          public void DeleteTestRecordsOfUser(string userId)
 262:          {
 263:              using (var db = new Ia.TentPlay.Db.Memorise())
 264:              {
 265:                  db.Database.ExecuteSqlCommand("delete from Scores where userId = {0}", userId);
 266:              }
 267:          }
 268:   
 269:          ////////////////////////////////////////////////////////////////////////////
 270:          ////////////////////////////////////////////////////////////////////////////    
 271:      }
 272:   
 273:      ////////////////////////////////////////////////////////////////////////////
 274:      ////////////////////////////////////////////////////////////////////////////   
 275:  }