test/VersionDictionary_test.cpp
author Jens Alfke <jens@mooseyard.com>
Sun Sep 20 15:14:12 2009 -0700 (2009-09-20)
changeset 0 31a43d94cc26
child 8 21a6c17f4e3e
permissions -rw-r--r--
First official checkin.
jens@0
     1
/*
jens@0
     2
 *  VersionDictionary_test.cpp
jens@0
     3
 *  Ottoman
jens@0
     4
 *
jens@0
     5
 *  Created by Jens Alfke on 9/2/09.
jens@0
     6
 *  Copyright 2009 Jens Alfke. All rights reserved.
jens@0
     7
 *  BSD-Licensed: See the file "LICENSE.txt" for details.
jens@0
     8
 */
jens@0
     9
jens@0
    10
jens@0
    11
#define VERSIONDICTIONARY_TESTING 1
jens@0
    12
jens@0
    13
#include <gtest/gtest.h>
jens@0
    14
#include "TestUtils.h"
jens@0
    15
#include "Chunk.h"
jens@0
    16
#include "File.h"
jens@0
    17
#include "VersionDictionary.h"
jens@0
    18
#include "Hash.h"
jens@0
    19
#include <fcntl.h>
jens@0
    20
#include <stdio.h>
jens@0
    21
jens@0
    22
using namespace Mooseyard;
jens@0
    23
jens@0
    24
jens@0
    25
class OverlayVersionDictionary :public OverlayDictionary {
jens@0
    26
public:
jens@0
    27
    OverlayVersionDictionary (File *file)
jens@0
    28
    :OverlayDictionary(new VersionDictionary(file))
jens@0
    29
    { }  
jens@0
    30
    
jens@0
    31
    int generation() const                  {return ((VersionDictionary*)base())->generation();}
jens@0
    32
    time_t timestamp() const                {return ((VersionDictionary*)base())->timestamp();}
jens@0
    33
jens@0
    34
    void save(){
jens@0
    35
        saveAs(((VersionDictionary*)base())->file());
jens@0
    36
    }
jens@0
    37
    
jens@0
    38
    void saveAs (File *dstFile) {
jens@0
    39
        VersionDictionary* oldBase = (VersionDictionary*) base();
jens@0
    40
        revertTo( ((VersionDictionary*)base())->_appendAndOpen(overlay(), dstFile, baseReplaced()) );
jens@0
    41
        delete oldBase;
jens@0
    42
    }
jens@0
    43
};
jens@0
    44
jens@0
    45
jens@0
    46
jens@0
    47
TEST(File,HasPath) {
jens@0
    48
    {
jens@0
    49
        File f("/tmp/jubba", O_RDWR | O_CREAT | O_TRUNC);
jens@0
    50
        f.write("howdy");
jens@0
    51
    }
jens@0
    52
    {
jens@0
    53
        File f("/tmp/jubba", O_RDWR);
jens@0
    54
        EXPECT_TRUE(f.hasPath("/tmp/jubba"));
jens@0
    55
        File::unlink("/tmp/jubba");
jens@0
    56
        EXPECT_FALSE(f.hasPath("/tmp/jubba"));
jens@0
    57
        
jens@0
    58
        File f2("/tmp/jubba", O_RDWR | O_CREAT | O_TRUNC);
jens@0
    59
        f2.write("howdy");
jens@0
    60
        f2.flush();
jens@0
    61
jens@0
    62
        EXPECT_FALSE(f.hasPath("/tmp/jubba"));
jens@0
    63
        EXPECT_TRUE(f2.hasPath("/tmp/jubba"));
jens@0
    64
    }
jens@0
    65
    File::unlink("/tmp/jubba");
jens@0
    66
}
jens@0
    67
jens@0
    68
jens@0
    69
static int TestIterate (File *file) {
jens@0
    70
    printf("Iterating the chunks...\n");
jens@0
    71
    int lastType = -1;
jens@0
    72
    int count = 0;
jens@0
    73
    int n = 0;
jens@0
    74
    ChunkIterator it(file, 4);
jens@0
    75
    for (; it; ++it) {
jens@0
    76
        uint16_t type = it.chunk()->type();
jens@0
    77
        if (type != lastType) {
jens@0
    78
            if (count > 0)
jens@0
    79
                printf("%6d\n", count);
jens@0
    80
            printf("type %u ... ", type);
jens@0
    81
            lastType = type;
jens@0
    82
            count = 0;
jens@0
    83
        }
jens@0
    84
        count++;
jens@0
    85
        EXPECT_LE(type, 3);
jens@0
    86
        if (type != 0)      // don't count padding chunks
jens@0
    87
            n++;
jens@0
    88
    }
jens@0
    89
    if (count > 0)
jens@0
    90
        printf("%6d\n", count);
jens@0
    91
    EXPECT_TRUE(it.atEOF());
jens@0
    92
    return n;
jens@0
    93
}    
jens@0
    94
jens@0
    95
jens@0
    96
static void TestWithWords (const int nWords) {
jens@0
    97
    ASSERT_EQ(8, sizeof(Chunk));
jens@0
    98
    ASSERT_EQ(8, sizeof(KeyValueChunk));
jens@0
    99
    
jens@0
   100
    printf("Building dictionary of %i words...\n", nWords);
jens@0
   101
    readWords();
jens@0
   102
    HashDictionary dict;
jens@0
   103
    for( int i=0; i<nWords; i++) {
jens@0
   104
        Blob kv(sWords[i]);
jens@0
   105
        dict.put(Key(kv),kv);
jens@0
   106
    }
jens@0
   107
    
jens@0
   108
    time_t startTime = ::time(NULL);
jens@0
   109
    time_t createTime;
jens@0
   110
    {
jens@0
   111
        File file("/tmp/hashfiletest", O_RDWR | O_CREAT | O_TRUNC);
jens@0
   112
        VersionDictionary *hf;
jens@0
   113
        {
jens@0
   114
            Timer t("Creating & writing VersionDictionary", nWords);
jens@0
   115
            file.write("Ha5h", 4);     // VersionDictionary won't write to an empty file
jens@0
   116
            hf = VersionDictionary::create(&file, &dict);
jens@0
   117
        }
jens@0
   118
        printf("File size: %llu bytes\n", file.length());
jens@0
   119
        ASSERT_TRUE(hf!=NULL);
jens@0
   120
        ASSERT_EQ(0, hf->generation());
jens@0
   121
        createTime = hf->timestamp();
jens@0
   122
        ASSERT_GE(createTime, startTime);
jens@0
   123
        ASSERT_LE(createTime, ::time(NULL));
jens@0
   124
        delete hf;
jens@0
   125
    }
jens@0
   126
    {
jens@0
   127
        File file("/tmp/hashfiletest");
jens@0
   128
        VersionDictionary hf(&file);
jens@0
   129
        ASSERT_EQ(0, hf.generation());
jens@0
   130
        ASSERT_EQ(createTime, hf.timestamp());
jens@0
   131
        {
jens@0
   132
            Timer t("Reading from VersionDictionary", nWords);
jens@0
   133
            EXPECT_EQ( nWords ,  hf.count() );
jens@0
   134
            for( int i=0; i<nWords; i++) {
jens@0
   135
                Key key(sWords[i]);
jens@0
   136
                Blob value = hf.get(key);
jens@0
   137
                ASSERT_TRUE(value);
jens@0
   138
                ASSERT_TRUE( value.equals(key) ) << "expected '" << key << "', got '" << value << "' (i=" << i <<")";
jens@0
   139
            }
jens@0
   140
        }
jens@0
   141
        
jens@0
   142
        printf("Iterating through the VersionDictionary...\n");
jens@0
   143
        Timer t("Iterating VersionDictionary", nWords);
jens@0
   144
        int n=0;
jens@0
   145
        for( VersionDictionary::Iterator it(&hf); it; ++it) {
jens@0
   146
            n++;
jens@0
   147
            ASSERT_TRUE(it.key().length > 0 && it.key().length < 50);
jens@0
   148
            ASSERT_TRUE(it.key().equals(it.value()));
jens@0
   149
            ASSERT_EQ( 0, ((size_t)it.value().bytes & 0x3) );  // 4-byte aligned
jens@0
   150
        }
jens@0
   151
        ASSERT_EQ(nWords, n);
jens@0
   152
    }
jens@0
   153
    {
jens@0
   154
        printf("Opening OverlayVersionDictionary...\n");
jens@0
   155
        File file("/tmp/hashfiletest", O_RDWR);
jens@0
   156
        OverlayVersionDictionary hf(&file);
jens@0
   157
        EXPECT_EQ( nWords ,  hf.count() );
jens@0
   158
        EXPECT_TRUE(hf.get("abatement").equals("abatement"));
jens@0
   159
        
jens@0
   160
        hf.put("abaser", "DEBASER");
jens@0
   161
        hf.put("growf", "growf");
jens@0
   162
        EXPECT_TRUE(hf.remove("abatement"));
jens@0
   163
        
jens@0
   164
        EXPECT_EQ( nWords, hf.count() );
jens@0
   165
        EXPECT_TRUE(hf.get("abaser").equals("DEBASER"));
jens@0
   166
        EXPECT_TRUE(hf.get("growf").equals("growf"));
jens@0
   167
        EXPECT_EQ( NULL, hf.get("abatement").bytes );
jens@0
   168
        EXPECT_TRUE(!hf.contains("abatement"));
jens@0
   169
        
jens@0
   170
        int n=0;
jens@0
   171
        for( OverlayVersionDictionary::Iterator it(hf); it; ++it) {
jens@0
   172
            n++;
jens@0
   173
            ASSERT_TRUE(!it.key().equals("abatement"));
jens@0
   174
        }
jens@0
   175
        ASSERT_EQ(nWords, n);
jens@0
   176
        
jens@0
   177
        printf("Saving OverlayVersionDictionary...\n");
jens@0
   178
        {
jens@0
   179
            Timer t("Saving OverlayVersionDictionary");
jens@0
   180
            hf.save();
jens@0
   181
        }
jens@0
   182
        printf("File size: %llu bytes\n", file.length());
jens@0
   183
        
jens@0
   184
        EXPECT_EQ( nWords, hf.count() );
jens@0
   185
        EXPECT_TRUE(hf.get("abaser").equals("DEBASER"));
jens@0
   186
        EXPECT_TRUE(hf.get("growf").equals("growf"));
jens@0
   187
        EXPECT_EQ( NULL, hf.get("abatement").bytes );
jens@0
   188
        EXPECT_TRUE(!hf.contains("abatement"));
jens@0
   189
        
jens@0
   190
        n=0;
jens@0
   191
        for( OverlayVersionDictionary::Iterator it(hf); it; ++it) {
jens@0
   192
            n++;
jens@0
   193
            ASSERT_TRUE(!it.key().equals("abatement"));
jens@0
   194
        }
jens@0
   195
        ASSERT_EQ(nWords, n);
jens@0
   196
    }
jens@0
   197
    {
jens@0
   198
        printf("Re-opening OverlayVersionDictionary...\n");
jens@0
   199
        File file("/tmp/hashfiletest");
jens@0
   200
        OverlayVersionDictionary hf(&file);
jens@0
   201
        
jens@0
   202
        ASSERT_EQ(1, hf.generation());
jens@0
   203
        ASSERT_GE(hf.timestamp(), createTime);
jens@0
   204
        ASSERT_LE(hf.timestamp(), ::time(NULL));
jens@0
   205
        EXPECT_EQ( nWords ,  hf.count() );
jens@0
   206
        EXPECT_TRUE(hf.get("abaser").equals("DEBASER"));
jens@0
   207
        EXPECT_TRUE(hf.get("growf").equals("growf"));
jens@0
   208
        EXPECT_EQ( NULL, hf.get("abatement").bytes );
jens@0
   209
        EXPECT_TRUE(!hf.contains("abatement"));
jens@0
   210
        
jens@0
   211
        int n=0;
jens@0
   212
        for( OverlayVersionDictionary::Iterator it(hf); it; ++it) {
jens@0
   213
            n++;
jens@0
   214
            ASSERT_TRUE(!it.key().equals("abatement"));
jens@0
   215
        }
jens@0
   216
        ASSERT_EQ(nWords, n);
jens@0
   217
jens@0
   218
        n = TestIterate(&file);
jens@0
   219
        EXPECT_GE(n, nWords+1+4);
jens@0
   220
        if (nWords > 1000)
jens@0
   221
            EXPECT_GE(n, nWords+256+4);
jens@0
   222
    }
jens@0
   223
    {
jens@0
   224
        printf("Writing VersionDictionary to a new file...\n");
jens@0
   225
        File oldFile("/tmp/hashfiletest");
jens@0
   226
        OverlayVersionDictionary oldhf(&oldFile);
jens@0
   227
        
jens@0
   228
        File newFile("/tmp/hashfiletest2", O_RDWR | O_CREAT | O_TRUNC);
jens@0
   229
        newFile.write("Ha5h", 4);     // VersionDictionary won't write to an empty file
jens@0
   230
        oldhf.saveAs(&newFile);
jens@0
   231
        printf("File size: %llu bytes\n", newFile.length());
jens@0
   232
    }
jens@0
   233
    {
jens@0
   234
        printf("Opening new file...\n");
jens@0
   235
        File file("/tmp/hashfiletest2");
jens@0
   236
        OverlayVersionDictionary hf(&file);
jens@0
   237
        
jens@0
   238
        EXPECT_EQ( nWords ,  hf.count() );
jens@0
   239
        EXPECT_TRUE(hf.get("abaser").equals("DEBASER"));
jens@0
   240
        EXPECT_TRUE(hf.get("growf").equals("growf"));
jens@0
   241
        EXPECT_EQ( NULL, hf.get("abatement").bytes );
jens@0
   242
        EXPECT_TRUE(!hf.contains("abatement"));
jens@0
   243
        
jens@0
   244
        int n=0;
jens@0
   245
        for( OverlayVersionDictionary::Iterator it(hf); it; ++it) {
jens@0
   246
            n++;
jens@0
   247
            ASSERT_TRUE(!it.key().equals("abatement"));
jens@0
   248
        }
jens@0
   249
        ASSERT_EQ(nWords, n);
jens@0
   250
        
jens@0
   251
        n = TestIterate(&file);
jens@0
   252
        EXPECT_GE(n, nWords+1+1);
jens@0
   253
        if (nWords > 1000)
jens@0
   254
            EXPECT_EQ(nWords+256+1, n);
jens@0
   255
    }
jens@0
   256
}    
jens@0
   257
jens@0
   258
jens@0
   259
TEST(VersionDictionary,BuildSmall) {
jens@0
   260
    TestWithWords(100);
jens@0
   261
}
jens@0
   262
jens@0
   263
TEST(VersionDictionary,BuildLarge) {
jens@0
   264
    TestWithWords(sNWords);
jens@0
   265
}